-
Notifications
You must be signed in to change notification settings - Fork 470
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
Basic tests for WeakRef and FinalizationGroup #2192
Conversation
9d1462e
to
d6505e9
Compare
Failures from V8 with the --harmony-weak-refs flag:
These errors show the constructors are not setting the correct prototype if the NewTarget's prototype is not an object.
This error relates to tc39/proposal-weakrefs#131 |
FYI, V8 currently implements an older version of the spec, and even then has deficiencies against that. See https://bugs.chromium.org/p/v8/issues/detail?id=8179#c24 and further. Edit: After some spec updates, the main behavioral ones are that |
Sure, I only use any test results as informative data, the tests are against the specs, which work as the final source of truth for each assertion. The tests may become useful to fix the implementation after the updates.
I noticed that, and therefore we have tests for it as well. |
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.
Cursory review of the FinalizationGroup
tests is done. I haven't looked at WeakRef
yet.
test/built-ins/FinalizationGroup/prototype-from-newtarget-abrupt.js
Outdated
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/prototype/register/target-not-object-throws.js
Outdated
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/prototype/cleanupSome/callback-not-callable-throws.js
Show resolved
Hide resolved
...t-ins/FinalizationGroup/prototype/register/unregisterToken-not-object-or-undefined-throws.js
Outdated
Show resolved
Hide resolved
...t-ins/FinalizationGroup/prototype/register/unregisterToken-not-object-or-undefined-throws.js
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/prototype/unregister/unregisterToken-not-object-throws.js
Outdated
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/prototype/unregister/unregisterToken-not-object-throws.js
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/returns-new-object-from-constructor.js
Outdated
Show resolved
Hide resolved
d8 exposes a |
I'm not sure how spidermonkey is invoked for the tests but by default jsshell exposes a The interesting part in testing is in dealing with the interaction of jobs scheduling and garbage collection. If the If it helps, I've created a helper that allows me to await until an object was collected: https://github.com/mhofman/tc39-weakrefs-shim/blob/81645e4e96042f6e35bd6805d36f93db9ee46f5e/tests/collector-helper.ts#L18-L50 |
Looks like you're relying on I don't know if test262 wants tests that extend beyond the ES spec -- it might be good enough to just check that the finalizer has not run when we get to the microtask queue. |
Right, that's one of the challenges. The tests in my shim rely on setImmediate (internally polyfilled) because that's what the shim itself uses. It's the closest I could get to the microtask checkpoint that browser embedders use. I believe @gsathya, how does I think we need to find a solution here. Just testing the "was not collected in the same synchronous execution" part of the spec is not sufficient. @littledan, do you have any suggestions on how to test the parts of the spec that require execution of the host hooks? |
I don't think test262 needs to find a solution. Embedders are free to do whatever here as it's not mandated by the spec. Note that non collecting embedders are spec compliant, so they shouldn't fail any test262 tests. I wonder if these tests belong in Web platform tests instead as they test the spec defined by WHATWG/HTML. |
Right, but how should test262 go about testing the behavior of iterators and other parts that are only accessible after collection has occurred? For example the guard to make sure iterators are not used asynchronously. Those definitely belong here. |
I'm fine with deferring all that to web platform tests as well. What has test262 done for other language features that required extensive embedder hooks? |
From a cursory look, the atomics seem to have some agent integration with yield and sleep: #1617 Maybe a related And if gc is available, a Looking at the spec, another area that relies on host hooks is module import with the |
As @mhofman says, test262 has lots of hooks that can only be implemented by particular embedders, for example, to detach an ArrayBuffer. I think it would be possible to find similar hooks that would let us test WeakRefs in test262. We could also use a feature flag to indicate that certain HTML-analogous behavior is required (and turn off the test for environments which differ). If we can't figure out an acceptable way to reach full test coverage within test262, we could write web-platform-tests and other host-level test suites to fill the gaps. |
I'm up for this, as it matches behavior we already have in the specs. the
It's specified in the documentation for Test262:
yes, I've been coordinating this work with @rwaldron to have a proper hook in eshost and make sure
I'd like to experiment the hooks here to make sure we caught everything properly. WPT can be useful with perhaps some direct GC, but I'd like to see weakrefs being well implemented in other places like node and embedded js iot. It's such a fundamental piece of weakrefs and I'm really excited to have it. |
From my perspective, most of the next tests depends on a GC hook. I'd like to stop this work here and continue from a follow up PR. These can be called the basic tests. This should minimize review burnout for everyone. Anyone up to review the current coverage? |
I actually missed uploading the review addressing for #2192 (review) |
...uilt-ins/FinalizationGroup/prototype/cleanupSome/this-does-not-have-internal-cells-throws.js
Show resolved
Hide resolved
SGTM. I'm happy to add hooks to
SGTM.
@mhofman knows the spec best, it'd be great to get their review. @wingo, maybe too? |
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 looks like a correct set of tests for the API surface.
Seems like it's a lot of work to write all of these repetitive tests! I wonder if a harness analogous to idlharness.js could be useful for test262 to reduce this load in the future.
I'm looking forward to the second set of tests which gets at the core of WeakRefs, but I see no problem with landing this first set of tests earlier.
test/built-ins/FinalizationGroup/prototype/cleanupSome/callback-not-callable-throws.js
Show resolved
Hide resolved
|
||
var actual = WeakRef.prototype.hasOwnProperty('constructor'); | ||
|
||
// If implemented, it should conform to the spec text |
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 should be written in a way that engines which implement Annex B can reliably assert that the property exists. The previous directory structure provided a way to do this; we shouldn't regress just because normative optional is inline. Maybe normative-optional
could be a feature flag.
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 flag would make the tests results rely more on how the metadata is interpreted and this needs some coordination with people who maintain test runners. Otherwise the js code would just straight forward force a feature.
I'd prefer to discuss this in a follow up as well, if you don't mind.
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.
Minor changes and then I can land it
.../built-ins/FinalizationGroup/prototype/register/this-does-not-have-internal-target-throws.js
Show resolved
Hide resolved
...built-ins/FinalizationGroup/prototype/unregister/this-does-not-have-internal-cells-throws.js
Show resolved
Hide resolved
test/built-ins/FinalizationGroup/returns-new-object-from-constructor.js
Outdated
Show resolved
Hide resolved
@littledan I'm not sure why I can't reply to your comment, so I'm replying here...
You are seeing the updated file, but for whatever reason github didn't auto resolve my comments. Had you reviewed the commits, you'd see that @leobalter fixed that file: c6aadc7#diff-058bfda97628c83bd0f48b02903b9229 |
I think that's related to getting the false positive. This assertion is there to prevent the tests from false positives. like: var obj = {};
/* ... */
assert.sameValue(typeof obj.foo, 'function');
assert.throws(TypeError, function() {
obj.foo(42);
}, 'foo throws if argument is 42');
// The assertion above would also throw a TypeError if foo is not a function
// The test would pass with foo not being implemented. This is a recent style we've been trying to use preventing tests that pass before a feature is implemented. |
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.
@mhofman knows the spec best, it'd be great to get their review.
Sorry for the late review.
I'm wondering, should there be a specific test to make sure WeakRef
and FinalizationGroup
are subclassable?
The specs mentions that aspect, but I'm not sure if that's something that is usually tested explicitly.
|
||
/*--- | ||
esid: sec-finalization-group.prototype.register | ||
description: Throws a TypeError if this does not have a [[Cells]] internal slot |
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.
Small nitpick, but the test's file name mentions target
not cells
.
assert.throws(TypeError, function() { | ||
register.call({ ['[[Cells]]']: {} }, target); | ||
}, 'Ordinary object without [[Cells]]'); | ||
|
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.
Thinking that FinalizationGroup.prototype
probably shouldn't have a [[Cells]]
internal slot.
Opened tc39/proposal-weakrefs#143
I plan to have these tests, but they are low priority in the given checklist. It should be pretty easy to do it anyway. |
The following is a checklist of basic observable points of the proposed specs, it doesn't go deep into abstractions and it should be good enough to track an initial set of tests.
Markdown is not amazing to handle the checkboxes, I won't spend much time fixing this, it's fair enough as it is.
The WeakRef Constructor
https://tc39.github.io/proposal-weakrefs/#sec-weak-ref-constructor
WeakRef ( target )
https://tc39.github.io/proposal-weakrefs/#sec-weak-ref-target
[[proto]]
Properties of the WeakRef Constructor
https://tc39.github.io/proposal-weakrefs/#sec-properties-of-the-weak-ref-constructor
WeakRef.prototype
https://tc39.github.io/proposal-weakrefs/#sec-weak-ref.prototype
Properties of the WeakRef Prototype Object
WeakRef.prototype.deref ( )
https://tc39.github.io/proposal-weakrefs/#sec-weak-ref.prototype.deref
a. Perform ! KeepDuringJob(target).
b. [ ] Return target.
WeakRef.prototype [ @@toStringTag ]
https://tc39.github.io/proposal-weakrefs/#sec-weak-ref.prototype-@@tostringtag
The FinalizationGroup Constructor
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group-constructor
FinalizationGroup ( cleanupCallback )
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group-cleanup-callback
Properties of the FinalizationGroup Constructor
https://tc39.github.io/proposal-weakrefs/#sec-properties-of-the-finalization-group-constructor
FinalizationGroup.prototype
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype
Properties of the FinalizationGroup Prototype Object
https://tc39.github.io/proposal-weakrefs/#sec-properties-of-the-finalization-group-prototype-object
is an ordinary object.
FinalizationGroup.prototype.constructor
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype.constructor
FinalizationGroup.prototype.register ( target , holdings [, unregisterToken ] )
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype.register
a. [ ] If unregisterToken is not undefined, throw a TypeError exception.
b. [ ] Set unregisterToken to empty.
FinalizationGroup.prototype.unregister ( unregisterToken )
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype.unregister
a. If SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then
i. Remove cell from finalizationGroup.[[Cells]].
ii. Set removed to true.
FinalizationGroup.prototype.cleanupSome ( [ callback ] )
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype.cleanupSome
FinalizationGroup.prototype [ @@toStringTag ]
https://tc39.github.io/proposal-weakrefs/#sec-finalization-group.prototype-@@tostringtag
CreateFinalizationGroupCleanupIterator ( finalizationGroup )
https://tc39.github.io/proposal-weakrefs/#sec-createfinalizationgroupcleanupiterator
The %FinalizationGroupCleanupIteratorPrototype% Object
https://tc39.github.io/proposal-weakrefs/#sec-%finalizationgroupcleanupiterator%-object
%FinalizationGroupCleanupIteratorPrototype%.next ( )
https://tc39.github.io/proposal-weakrefs/#sec-%finalizationgroupcleanupiterator%.next
a. [ ] Return CreateIterResultObject(undefined, true).
a. Choose any such cell.
b. Remove cell from finalizationGroup.[[Cells]].
c. [ ] Return CreateIterResultObject(cell.[[Holdings]], false).
%FinalizationGroupCleanupIteratorPrototype% [ @@toStringTag ]
https://tc39.github.io/proposal-weakrefs/#sec-%finalizationgroupcleanupiteratorprototype%-@@tostringtag