-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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 property based tests on diff-sequences #9072
Conversation
const allData = flatten(data); // [...data[0], ...data[1], ...data[2], ...data[3], ...] | ||
const partialData = flatten(data.filter((_, i) => i % 2 === 1)) // [...data[1], ...data[3], ...] | ||
const commonItems = findCommonItems(allData, partialData) | ||
expect(commonItems.length).toBeGreaterThanOrEqual(partialData.length) |
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 test also passes with toEqual
which I think makes it similar to the preceding test. What do you think?
Exploring what it would look like to use the preceding test alone to assert the property:
it('should find subsequence', () => {
fc.assert(fc.property(
fc.array(fc.char()), fc.array(fc.char()),
(a, b) => {
const commonItems = findCommonItems(a, b)
expect(findCommonItems(a, commonItems)).toEqual(commonItems)
expect(findCommonItems(commonItems, a)).toEqual(commonItems)
expect(findCommonItems(b, commonItems)).toEqual(commonItems)
expect(findCommonItems(commonItems, b)).toEqual(commonItems)
}
))
});
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.
If I am right your suggestion for should find subsequence
is close to should be no-op when passing common items
: it adds the b-based cases.
💭 Let's suppose for a minute that we remove the test called should find at the least the maximal known subset
...
In that case if we use findCommonItems = (a, b) => []
all the properties will pass. None of them are checking that there are at least some items - because they actually cannot do so given the few assumptions they have on the inputs.
Actually this last test is the only test covering the we expect at least N entries in the list of common items
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.
Update: should be reflexive
would be error in the scenario described above
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.
What do you think if the assertion becomes: expect(commonItems).toEqual(partialData)
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're totally right as we have both:
expect(commonItems.length).toBeGreaterThanOrEqual(partialData.length)
expect(commonItems.length).toBeLessThanOrEqual(partialData.length)
// rule we use for 'should have at most the length of its inputs'
We have: expect(commonItems).toEqual(partialData)
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 makes this it
much more useful as it produces sets of entries for which we know what are the exact outputs.
You can ignore my comment:
It might even replace my hacky test:
should find at the least the maximal known subset
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, in the last test, let‘s assert the items themselves instead of the length.
If you agree in the second to last test, let‘s include assertions for both a
and b
and replace “no-op” in name with something more descriptive
import diff from '../'; | ||
import fc from 'fast-check' | ||
|
||
const findCommonItems = (a: string[], b: string[]): string[] => { |
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.
lint-and-typecheck
failed on CI with Array type using 'string[]' is forbidden. Use 'Array<string>' 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.
Will do
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.
Thank you. It looks like a few more lint errors. Does yarn lint --fix
locally display them?
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 thought I did, I'll retry
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.
@pedrottimark This time I did it for sure ^^ I might not be at head. Maybe I could just merge onto master on branch to get the latest changes
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.
Ohhh, now it’s about the Facebook comment at the beginning of the file. I always forget it.
You can copy and paste from index.test.ts
file
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.
Got it: Facebook copyright header check failed for the following files
Nicolas, thank you for this practical tutorial on property-based testing! Beyond the scope of this pull request, is there a generic name for a test that compares the package to a short but slow implementation of diff for random inputs? |
Such test would be pretty useful - testing the optimal implementation against a dummy one that just does the job. It might even replace my hacky test: I have no generic naming for it. But we can name it something like: |
Super, I will find my quadratic implementation in JavaScript and convert to TypeScript Do you recommend (in future pull request) that I add it to this test file or add a separate test file? |
As you like ;) But really good idea to add this one ;) If we want to go further we can even go further by adding yet another test:
Can be seen as a variant of |
I added the test I was talking about in my previous comment here: 5c2e725 |
After some time in my mental slow cooker, I remembered some pieces that might interest you:
const isSubsequenceOf = (
subsequence: Array<string>,
sequence: Array<string>,
): boolean => {
let iSub = 0;
let iSeq = 0;
while (iSub !== subsequence.length && iSeq !== sequence.length) {
if (subsequence[iSub] === sequence[iSeq]) {
iSub += 1;
}
iSeq += 1;
}
return iSub === subsequence.length;
}; Would you like to add a test of random sequences which asserts
Because the last test constructs a subsequence of a sequence, it can replace assertion about number of items with assertion about the items themselves:
|
Codecov Report
@@ Coverage Diff @@
## master #9072 +/- ##
==========================================
- Coverage 64.07% 64.05% -0.03%
==========================================
Files 277 277
Lines 11681 11676 -5
Branches 2863 2862 -1
==========================================
- Hits 7485 7479 -6
Misses 3572 3572
- Partials 624 625 +1
Continue to review full report at Codecov.
|
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.
Thanks again! This looks ready to merge if you are happy with it.
I'm happy with it, we can go ahead |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
When I added the first property based tests in Jest codebase - see #8012 - @pedrottimark asked me:
This PR adds property based tests to check diff-sequences.
I think we should find better namings for some of the tests I added 🤔
Test plan
PR only adds tests.