-
Notifications
You must be signed in to change notification settings - Fork 52
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
Fix capability checking, and refactor/add lots of comments #959
Conversation
ignoreOK (ds, _miss) = (ds, []) | ||
|
||
(deviceSets, missingDeviceSets) = | ||
Lens.over both (nubOrd . map S.fromList) . unzip $ |
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.
The bug was in the fact that we did a nubOrd
here --- which could change the length of the list...
|
||
formatDevices = T.intercalate " or " . map (^. entityName) . S.toList | ||
-- capabilities not provided by any device in inventory | ||
missingCaps = S.fromList . map fst . filter (null . snd) $ zip caps deviceSets |
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.
... but here we zip
ped that possibly-shorter list with caps
, which started out having the same length. But with repeated things that got nubbed away, the two lists were no longer aligned, which sometimes caused the wrong devices to be suggested for an unrelated missing capability.
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.
The detailed comments are great! 👍
We should really split the Step
module, it just keeps growing. 😅
EDIT:
Honestly not sure how to write automated tests for this, any ideas?
I would add a test scenario with several entities providing the same capabilities that would trigger the wrong behaviour in the original version.
For sure! EDIT: fortunately someone has already written a nice description of how we might do this! #707 😄
Sure, good idea. |
Oh, now I remember why this is tricky. The problem is that the bug is a wrong error message. In other words this issue only triggers in a scenario where we should get an error message, but we just get the wrong one. There's no way to make a scenario that would fail without this fix but succeed with it. To see whether the fix worked you have to actually inspect the text of the error message. @xsebek do you know how to inspect the text of generated exceptions as part of an integration test? I vaguely seem to recall that you have done that kind of thing before. EDIT: oh, I think I figured it out: we can use |
Added a test case and confirmed it fails on current |
, testSolution' Default "Testing/397-wrong-missing" AllowBadErrors $ \g -> do | ||
let msgs = | ||
(g ^. messageQueue . to seqToTexts) | ||
<> (g ^.. robotMap . traverse . robotLog . to seqToTexts . traverse) |
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.
Those are some impressive optics. 🤓
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.
Haha, thanks, though I don't think it's that bad: ^..
means to list all the targets of a Traversal
instead of just projecting out a single value. traverse
just gets all the sub-things. So this means "get the robot map, then get all the robots out of it, and for each one get its log, convert it to a list of texts..." The last traverse
is just so we get a single list of texts instead of a list of lists.
Co-authored-by: Ondřej Šebek <[email protected]>
I've found that an effective strategy for this kind of issue is to define a global sum type for all possible errors, and adopt this as a standard for errors across the codebase. Any relevant information at the error site is collected in the fields of this sum type's constructors, which is separately used by some toplevel error-message-rendering function to produce the human-readable text. Then the test suite can pattern match on the error enum for circumstances where a certain error is expected to be produced. |
Yes, that's a nice strategy, and we already do that to some extent with our |
Fixes #397. The only way I could understand this in order to fix it was to totally refactor the code and add lots of comments as I went. I feel like this is some of the most difficult code to wrap one's head around in the codebase. Hopefully now it's a bit easier to understand (though still not easy, I imagine).