-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid using Opt.auto to avoid overflows going silent #864
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the direction, but wordReader
needs some polishing. 😃
0789ab6
to
9ed78dd
Compare
@carbolymer> I did the changes 👍 Given your last comment, I assume you're fine with me deploying this to many more code locations? (please don't approve though yet, because I'll extend this PR). |
dda38ff
to
62973d5
Compare
105c015
to
d3abc03
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Now just replace all calls to auto
.
d3abc03
to
6483900
Compare
6483900
to
76b6252
Compare
8317ab1
to
13f04eb
Compare
49fc27e
to
44ca6ed
Compare
pairIntegralReader :: (Typeable a, Integral a, Bits a) => ReadM (a, a) | ||
pairIntegralReader = readerFromParsecParser pairIntegralParsecParser | ||
|
||
pairIntegralParsecParser :: (Typeable a, Integral a, Bits a) => Parsec.Parser (a, a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is important to review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks fine to me 👌🏻
-- @cabal test cardano-cli-test --test-options '-p "/pair integral reader/"'@ | ||
hprop_pair_integral_reader :: Property | ||
hprop_pair_integral_reader = propertyOnce $ do | ||
assert $ isRight $ parse @Word "(0, 0)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can improve these tests with hedgehog generators. Example:
diff --git a/cardano-cli/test/cardano-cli-test/Test/Cli/Parser.hs b/cardano-cli/test/cardano-cli-test/Test/Cli/Parser.hs
index 1bf19f8b8..c72c8a093 100644
--- a/cardano-cli/test/cardano-cli-test/Test/Cli/Parser.hs
+++ b/cardano-cli/test/cardano-cli-test/Test/Cli/Parser.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Test.Cli.Parser
@@ -12,11 +14,14 @@ import Cardano.CLI.EraBased.Options.Common (integralParsecParser,
import Data.Bits (Bits)
import Data.Data (Typeable)
import Data.Either (isLeft, isRight)
+import Data.Proxy
import Data.Word (Word16)
import qualified Text.Parsec as Parsec
-import Hedgehog (Property, assert)
+import Hedgehog
import Hedgehog.Extras (propertyOnce)
+import qualified Hedgehog.Gen as Gen
+import qualified Hedgehog.Range as Range
-- | Execute me with:
-- @cabal test cardano-cli-test --test-options '-p "/integral reader/"'@
@@ -45,9 +50,8 @@ hprop_integral_reader = propertyOnce $ do
-- @cabal test cardano-cli-test --test-options '-p "/pair integral reader/"'@
hprop_pair_integral_reader :: Property
hprop_pair_integral_reader = propertyOnce $ do
- assert $ isRight $ parse @Word "(0, 0)"
- assert $ isRight $ parse @Word " ( 0 , 0 )"
- assert $ isRight $ parse @Word " (18446744073709551615 , 18446744073709551614 ) "
+ validArbitraryTuple <- forAll $ genNumberTuple (Proxy :: Proxy Word)
+ assert $ isRight $ parse @Word validArbitraryTuple
assert $ isLeft $ parse @Word "(0, 0, 0)"
assert $ isLeft $ parse @Word "(-1, 0)"
@@ -64,3 +68,18 @@ hprop_pair_integral_reader = propertyOnce $ do
case Parsec.runParser pairIntegralParsecParser () "" s of
Left parsecError -> Left $ show parsecError
Right x -> Right x
+
+genNumberTuple
+ :: forall integral
+ . Integral integral
+ => Show integral
+ => Proxy integral -> Gen String
+genNumberTuple _ = do
+ x :: integral <- Gen.integral (Range.linear 0 100)
+ y :: integral <- Gen.integral (Range.linear 0 100)
+ space1 <- genArbitrarySpace
+ space2 <- genArbitrarySpace
+ return $ "(" ++ space2 ++ show x ++ space1 ++ "," ++ space2 ++ show y ++ space1 ++ ")"
+
+genArbitrarySpace :: Gen String
+genArbitrarySpace = Gen.string (Range.linear 0 5) (return ' ')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should as much as possible avoid unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took your suggestion and split the function into two, since the positive tests need to be run with property
, while the negative tests need to run with propertyOnce
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while the negative tests need to run with propertyOnce
Why? You could also write a generator to inject a random character (or multiple characters) between the brackets for the negative tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but I would need to rule out generators that would still yield a valid value (e.g. if the generated character is a number) and I believe writing a good generator for negative tests it overkill for testing this parser. So I'll stick to the manual negative tests to speed up merging.
44ca6ed
to
7b12b6b
Compare
7b12b6b
to
fc9d434
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM however you can improve your tests further using hedgehog generators.
-- @cabal test cardano-cli-test --test-options '-p "/integral reader/"'@ | ||
hprop_integral_reader :: Property | ||
hprop_integral_reader = propertyOnce $ do | ||
assert $ isRight $ parse @Word "0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use https://hackage.haskell.org/package/hedgehog-1.5/docs/Hedgehog-Internal-Gen.html#v:word instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Done with:
w <- forAll $ Gen.word $ Gen.linear minBound maxBound
assert $ isRight $ parse @Word (show w)
validArbitraryTuple <- forAll $ genNumberTuple (Proxy :: Proxy Word) | ||
assert $ isRight $ parse @Word validArbitraryTuple | ||
|
||
assert $ isLeft $ parse @Word "(0, 0, 0)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can write a generator that injects a random character (or characters) into the string generated by genNumberTuple
. This would provide better coverage.
assert $ isLeft $ parse @Word "(0, 0, 0)" | ||
assert $ isLeft $ parse @Word "(-1, 0)" | ||
assert $ isLeft $ parse @Word "(18446744073709551616, 0)" | ||
assert $ isLeft $ parse @Word "(0, 18446744073709551616)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are already tested in hprop_integral_pair_reader_negative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops, good catch. Correcting 👍
fc9d434
to
a2521c1
Compare
hprop_integral_reader :: Property | ||
hprop_integral_reader = property $ do | ||
assert $ isRight $ parse @Word "0" | ||
assert $ isRight $ parse @Word "42" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be better to check the exact value in case of Right
s here
assert $ isRight $ parse @Word "42" | |
parse @Word "42" === Right 42 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, changing 👍
assert $ isRight $ parse @Word "0" | ||
assert $ isRight $ parse @Word "42" | ||
assert $ isLeft $ parse @Word "-1" | ||
assert $ isLeft $ parse @Word "18446744073709551616" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to write this as
assert $ isLeft $ parse @Word "18446744073709551616" | |
assertWith isLeft $ parse @Word "18446744073709551616" |
assert
does not report the value on assertion failure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to (for example) assertWith (parse @Word "18446744073709551616") isLeft
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
a2521c1
to
b4ab08a
Compare
Changelog
Context
We use auto a lot in parsing.
auto
relies under the hood on Read instances which are known to have problems. Some instances accept wrong values and return out of thin air values. This PR fixes this.Fixes #860
How to trust this PR
cardano-testnet
: testedcabal test cardano-testnet-test
withcardano-node
at e9ab511272a7694196778007211991a9984557e8 andcardano-cli
at 44ca6edgit grep auto "*.hs"
and observe that all the remaining calls are in abyron
file (I didn't change those)Checklist