Skip to content
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

Add test for validateFlatTerm and round trip test for FlatTerm conversions #196

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

DeepakKapiswe
Copy link
Contributor

@DeepakKapiswe DeepakKapiswe commented Mar 22, 2019

  • Tests for validateFlatTerm function
  • Travis: GHC versions update
  • Add round trip property tests for FlatTerm to / from conversion

@DeepakKapiswe DeepakKapiswe force-pushed the moretests branch 3 times, most recently from 780d172 to 6dab918 Compare March 25, 2019 07:39
@DeepakKapiswe DeepakKapiswe changed the title Add Test for validateFlatTerm function Add test for validateFlatTerm and round trip test for FlatTerm conversions Mar 26, 2019
@DeepakKapiswe DeepakKapiswe force-pushed the moretests branch 4 times, most recently from 4464bf9 to 30eff8a Compare March 27, 2019 07:09
Copy link
Member

@dcoutts dcoutts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good. The first main patch (ignoring the CI one) is good and just needs a few adjustments. The second patch will need re-thinking, at least the property for invalid flat terms. It'd be ok to split this into two if you like so we can commit the first patch sooner.

imp = fromRef . canonicaliseRef $ x
eq = eqImp t
enc = encodeImp t imp
fn e = fromFlatTerm (decodeImp (Proxy :: Proxy t)) $ toFlatTerm e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be decodeImp t rather than decodeImp (Proxy :: Proxy t), since we already defined the value t as Proxy :: Proxy t (where the latter t is the type).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

prop_toFromFlatTerm :: forall t. Token t => Proxy t -> t -> Bool
prop_toFromFlatTerm _ x =

liftA2 eq (fn enc) (Right imp) == Right True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be expressed a bit more elegantly if you followed the same trick as deserialiseImp which is basically a wrapper that throws an exception of the result is a decode failure.

Here, you'd make a local wrapper around fromFlatTerm that just throws an exception in the Left case. Something like

  where
    deserialiseFromFlatTerm dec =
      case fromFlatTerm dec flatterm of
        Left _ -> error "fromFlatTerm: decode failure"
        Right x -> x

Then your overall property can match the diagram directly (and like in your comment).

(deserialiseFromFlatTerm (decodeImp t) . toFlatTerm . encodeImp t) imp  `eq`  imp

The idea with these commuting diagrams is that the property can be read off directly by composing all the arrows. So this reads most nicely when the property is exactly that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct Implemented accordingly.



-- Convert Term to List of Valid TermTokens
termToValidTermTokens :: Term -> [TermToken]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be replaced by toFlatTerm . encodeTerm couldn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

prop_validateValidFlat (ValidFlat ts) = property $ validFlatTerm ts

prop_validateInValidFlat :: InValidFlat -> Property
prop_validateInValidFlat (InValidFlat ts) = property $ validFlatTerm ts == False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very add-hoc property. The generator for InValidFlat is just using various but fixed ways of making an invalid flat term.

I'm not happy with adding this property. It looks like it's testing something that it's really not testing well.

An alternative approach would be to naively generate arbitrary flat terms and then check that the reference decoder (ie from Tests.Reference.Implementation) agrees with validFlatTerm. By agree, I mean they both agree it's valid, or both agree it's invalid. Of course most arbitrarily generated flat terms will be invalid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dcoutts Yes I agree you are right, the generation of InvalidFlat is ad hoc in the sense that it is not covering all possible ways of invalidity but a few fixed ones.

Alternative approach looks fine to me btw do you think that testing arbitrarily generated FlatTerms along with the current setup will be better or its of no use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the currently proposed change here is misleading, and not of a lot of use. I'd accept the PR without the second patch. Or I'd accept the second patch without the bogus property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the property as per your suggestions!

@DeepakKapiswe DeepakKapiswe force-pushed the moretests branch 3 times, most recently from e67919c to 7c3e62c Compare May 15, 2019 11:23
prop_validFlatTerm :: [TermToken] -> Property
prop_validFlatTerm ts = property $ case refImpDecode ts of
(Just x, Just y) -> x == y && validFlatTerm ts
(Nothing, Nothing) -> True && (not $ validFlatTerm ts)
Copy link
Contributor

@erikd erikd May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that position True does absolutely nothing. You should drop it an just leave the not (validFlatTerm ts).

Basically for all values of x, True && x == x.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have the logic right here (ie prop_validFlatTerm and refImpDecode) but the structure is a bit weird. Specifically, you have an function that encodes a pair two different ways and returns them as a tuple, when a large chunk of that could just be inlined in the property. Once you inline like that, you probably don't need maybeRdecoded you can just pattern match on an (Maybe a, Either e a) pair.

Copy link
Contributor

@erikd erikd May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While i think the above is logically correct, I think that the QC generated [TermToken] data will be invalid for all but the most trivial cases. It would be much nicer if we could manipulate this so that it generated terms that were valid say 80% of the time and invalid 20% of the time. This would give us much better assurance that this property is getting thoroughly tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented the requested changes!

--
prop_toFromFlatTerm :: forall t. Token t => Proxy t -> t -> Bool
prop_toFromFlatTerm _ x =

liftA2 eq (fn enc) (Right imp) == Right True
(deserialiseFromFlatTerm (decodeImp t) . toFlatTerm . encodeImp t) imp `eq` imp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably use QuickCheck's === operator there because if the property fails === gives a much better error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, eq is not directly equivalent to QC's === as eq is defined as eq = eqImp t and eqImp is a method of TypeClass Token for which the test property is written.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok. Disregard that comment then.

@DeepakKapiswe DeepakKapiswe force-pushed the moretests branch 2 times, most recently from 5f1fa38 to 761ef0c Compare May 17, 2019 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants