--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
--
Instead, you should use a captureless lambda (which decays to a function pointer), and bind anything you wish with base::Bind:net_test_task_runner_->PostTask(FROM_HERE, base::Bind([](WhateverTheTypeOfThisIs* self) {self->AFixtureMethodBoundToThisPtr();(and more test code)}, base::Unretained(this));net_test_task_runner_->RunUntilIdle();
Re. binding |this| into an explicit |self| pointer : right that works it just makes the whole paradigm I'm trying to introduce much more cumbersome than desired :(. I want it to be easy to read the test in one block knowing that various blocks execute in various task contexts.
Re. can't guarantee lifetime : it's true that one has to be careful with captures and lifetime but this case should be fine per execution happening synchronously right after binding.
Re. notes linked by PK : right, read those before posting this but they don't mention this unless I missed it (from my reading they merely say what I already know : that capturing is risky if not done properly).
Re. can't guarantee lifetime : it's true that one has to be careful with captures and lifetime but this case should be fine per execution happening synchronously right after binding.
Re. notes linked by PK : right, read those before posting this but they don't mention this unless I missed it (from my reading they merely say what I already know : that capturing is risky if not done properly).
I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
I looked at the first 10 files on codesearch
On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.
In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.
On Mon, Feb 13, 2017 at 5:29 PM Daniel Cheng <dch...@chromium.org> wrote:On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.I agree that base::Unretained() should always be accompanied by a comment stating why it's safe (unless it's blatantly obvious -- e.g. in unit tests binding the test fixture).base::BindWithCapture() is essentially the same as base::Unretained(), i.e. it doesn't force documentation but it's at least an explicit name that requires dev/reviewer to think about it and documents it for future readers. I don't see why one is okay but not the other.
In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.I'm hoping to move unit testing to a world where every task runner runs on the main thread but ThreadTaskRunnerHandle/RunsTasksOnCurrentThread/etc. respond to being in its scope (not being on main thread) -- with escape hatches for the few tests that absolutely need async. That way we can easily run multi-threaded tests on the main thread (and deterministically run phases of the test as desired + mock tick clocks, yay!).To achieve this it needs to be easy/pretty to have test code run in the context of one of those runners and being able to capture |this| is essential to avoid this paradigm being too verbose to be nice to use.
On Tue, Feb 14, 2017 at 11:08 AM, Gabriel Charette <g...@chromium.org> wrote:On Mon, Feb 13, 2017 at 5:29 PM Daniel Cheng <dch...@chromium.org> wrote:On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.I agree that base::Unretained() should always be accompanied by a comment stating why it's safe (unless it's blatantly obvious -- e.g. in unit tests binding the test fixture).base::BindWithCapture() is essentially the same as base::Unretained(), i.e. it doesn't force documentation but it's at least an explicit name that requires dev/reviewer to think about it and documents it for future readers. I don't see why one is okay but not the other.I think we don't need two ways to do this, and Unretained is more general, and already used everywhere.In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.I'm hoping to move unit testing to a world where every task runner runs on the main thread but ThreadTaskRunnerHandle/RunsTasksOnCurrentThread/etc. respond to being in its scope (not being on main thread) -- with escape hatches for the few tests that absolutely need async. That way we can easily run multi-threaded tests on the main thread (and deterministically run phases of the test as desired + mock tick clocks, yay!).To achieve this it needs to be easy/pretty to have test code run in the context of one of those runners and being able to capture |this| is essential to avoid this paradigm being too verbose to be nice to use.Why doesn't a helper function that produces a Callback and binds this into it or something like that work?
On Tue, Feb 14, 2017 at 11:12 AM <dan...@chromium.org> wrote:On Tue, Feb 14, 2017 at 11:08 AM, Gabriel Charette <g...@chromium.org> wrote:On Mon, Feb 13, 2017 at 5:29 PM Daniel Cheng <dch...@chromium.org> wrote:On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.I agree that base::Unretained() should always be accompanied by a comment stating why it's safe (unless it's blatantly obvious -- e.g. in unit tests binding the test fixture).base::BindWithCapture() is essentially the same as base::Unretained(), i.e. it doesn't force documentation but it's at least an explicit name that requires dev/reviewer to think about it and documents it for future readers. I don't see why one is okay but not the other.I think we don't need two ways to do this, and Unretained is more general, and already used everywhere.In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.I'm hoping to move unit testing to a world where every task runner runs on the main thread but ThreadTaskRunnerHandle/RunsTasksOnCurrentThread/etc. respond to being in its scope (not being on main thread) -- with escape hatches for the few tests that absolutely need async. That way we can easily run multi-threaded tests on the main thread (and deterministically run phases of the test as desired + mock tick clocks, yay!).To achieve this it needs to be easy/pretty to have test code run in the context of one of those runners and being able to capture |this| is essential to avoid this paradigm being too verbose to be nice to use.Why doesn't a helper function that produces a Callback and binds this into it or something like that work?It's 50 lines of code that should all run on the |net_test_task_runner_| (all of the methods invoked DCHECK(net_test_task_runner_->RunsOnCurrentThread()). Currently this happens to pass despite this code running in the main thread's context because TestMockTimeTaskRunner::RunsOnCurrentThread() is looser than I'd like (it checks the thread id instead of whether it's truly currently executing something in its context).This is a problem because it means that if any of the tested code uses ThreadTaskRunnerHandle::Get(), it'll get the main thread's task runner instead of |net_test_task_runner_| (which is wrong given it just verified it's running on |net_test_task_runner_| -- and blocks https://codereview.chromium.org/2491613004/).A helper function either has to bind |this| inline (and become verbose) or be a method on the test fixture (which makes the test hard to read -- its body essentially moves to the test fixture...).The cleanest test code would be to have the test code inline in the test body, merely encapsulated in a lambda that captures [this].I expect this test pattern to be more and more common as we move more and more things to independent sequences and services and having a nice test paradigm to follow here will help make our tests (and thus codebase) healthier.Gab
On Tue, Feb 14, 2017 at 11:12 AM <dan...@chromium.org> wrote:On Tue, Feb 14, 2017 at 11:08 AM, Gabriel Charette <g...@chromium.org> wrote:On Mon, Feb 13, 2017 at 5:29 PM Daniel Cheng <dch...@chromium.org> wrote:On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.I agree that base::Unretained() should always be accompanied by a comment stating why it's safe (unless it's blatantly obvious -- e.g. in unit tests binding the test fixture).base::BindWithCapture() is essentially the same as base::Unretained(), i.e. it doesn't force documentation but it's at least an explicit name that requires dev/reviewer to think about it and documents it for future readers. I don't see why one is okay but not the other.I think we don't need two ways to do this, and Unretained is more general, and already used everywhere.In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.I'm hoping to move unit testing to a world where every task runner runs on the main thread but ThreadTaskRunnerHandle/RunsTasksOnCurrentThread/etc. respond to being in its scope (not being on main thread) -- with escape hatches for the few tests that absolutely need async. That way we can easily run multi-threaded tests on the main thread (and deterministically run phases of the test as desired + mock tick clocks, yay!).To achieve this it needs to be easy/pretty to have test code run in the context of one of those runners and being able to capture |this| is essential to avoid this paradigm being too verbose to be nice to use.Why doesn't a helper function that produces a Callback and binds this into it or something like that work?It's 50 lines of code that should all run on the |net_test_task_runner_| (all of the methods invoked DCHECK(net_test_task_runner_->RunsOnCurrentThread()). Currently this happens to pass despite this code running in the main thread's context because TestMockTimeTaskRunner::RunsOnCurrentThread() is looser than I'd like (it checks the thread id instead of whether it's truly currently executing something in its context).This is a problem because it means that if any of the tested code uses ThreadTaskRunnerHandle::Get(), it'll get the main thread's task runner instead of |net_test_task_runner_| (which is wrong given it just verified it's running on |net_test_task_runner_| -- and blocks https://codereview.chromium.org/2491613004/).A helper function either has to bind |this| inline (and become verbose) or be a method on the test fixture (which makes the test hard to read -- its body essentially moves to the test fixture...).The cleanest test code would be to have the test code inline in the test body, merely encapsulated in a lambda that captures [this].I expect this test pattern to be more and more common as we move more and more things to independent sequences and services and having a nice test paradigm to follow here will help make our tests (and thus codebase) healthier.
On Tue, Feb 14, 2017 at 11:36 AM, Gabriel Charette <g...@chromium.org> wrote:On Tue, Feb 14, 2017 at 11:12 AM <dan...@chromium.org> wrote:On Tue, Feb 14, 2017 at 11:08 AM, Gabriel Charette <g...@chromium.org> wrote:On Mon, Feb 13, 2017 at 5:29 PM Daniel Cheng <dch...@chromium.org> wrote:On Mon, Feb 13, 2017 at 2:17 PM Gabriel Charette <g...@chromium.org> wrote:I'm all for forcing explicit markups so that devs are forced to make a call and so that it acts as documentation to reviewer and reader.
But could we have base::BindWithCapture() or something as an explicit thing for people that know what they are doing?
base::Unretained() is a similar construct (I know what I'm doing and I promise it's safe), but it's frequently used with no comment as to why it's safe: I looked at the first 10 files on codesearch that used base::Unretained() and found one comment explaining why Unretained is safe. I think introducing BindWithCapture() would have the same issues.I agree that base::Unretained() should always be accompanied by a comment stating why it's safe (unless it's blatantly obvious -- e.g. in unit tests binding the test fixture).base::BindWithCapture() is essentially the same as base::Unretained(), i.e. it doesn't force documentation but it's at least an explicit name that requires dev/reviewer to think about it and documents it for future readers. I don't see why one is okay but not the other.I think we don't need two ways to do this, and Unretained is more general, and already used everywhere.In the end, it just doesn't seem like a common enough use case, nor one that should be encouraged, given how complex Bind() already is.I'm hoping to move unit testing to a world where every task runner runs on the main thread but ThreadTaskRunnerHandle/RunsTasksOnCurrentThread/etc. respond to being in its scope (not being on main thread) -- with escape hatches for the few tests that absolutely need async. That way we can easily run multi-threaded tests on the main thread (and deterministically run phases of the test as desired + mock tick clocks, yay!).To achieve this it needs to be easy/pretty to have test code run in the context of one of those runners and being able to capture |this| is essential to avoid this paradigm being too verbose to be nice to use.Why doesn't a helper function that produces a Callback and binds this into it or something like that work?It's 50 lines of code that should all run on the |net_test_task_runner_| (all of the methods invoked DCHECK(net_test_task_runner_->RunsOnCurrentThread()). Currently this happens to pass despite this code running in the main thread's context because TestMockTimeTaskRunner::RunsOnCurrentThread() is looser than I'd like (it checks the thread id instead of whether it's truly currently executing something in its context).This is a problem because it means that if any of the tested code uses ThreadTaskRunnerHandle::Get(), it'll get the main thread's task runner instead of |net_test_task_runner_| (which is wrong given it just verified it's running on |net_test_task_runner_| -- and blocks https://codereview.chromium.org/2491613004/).A helper function either has to bind |this| inline (and become verbose) or be a method on the test fixture (which makes the test hard to read -- its body essentially moves to the test fixture...).The cleanest test code would be to have the test code inline in the test body, merely encapsulated in a lambda that captures [this].I expect this test pattern to be more and more common as we move more and more things to independent sequences and services and having a nice test paradigm to follow here will help make our tests (and thus codebase) healthier.I think there's 2 pretty reasonable ways to do this that don't involve binding this into a lambda:
1. Move the code into a methodHttpServerPropertiesManagerTest::RunConfirmAlternativeService(WaitableEvent* event) {
// Move all the test code here..event->Signal();}WaitableEvent event;auto callback = base::Bind(&HttpServerPropertiesManagerTest::RunConfirmAlternativeService, base::Unretained(this), &event);net_test_task_runner_->PostTask(std::move(callback));event.Wait();}
2. Bind the lambda without this.TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) {auto lambda = [](HttpServerPropertiesManagerTest* self, WaitableEvent* event) {// Move all the test code here.. and use public instead of private members.event->Signal();}WaitableEvent event;auto callback = base::Bind(lambda, base::Unretained(this), &event);net_test_task_runner_->PostTask(std::move(callback));event.Wait();}
Neither of these seem particularly painful to me. Do they do you?
2. Bind the lambda without this.TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) {auto lambda = [](HttpServerPropertiesManagerTest* self, WaitableEvent* event) {// Move all the test code here.. and use public instead of private members.event->Signal();}WaitableEvent event;auto callback = base::Bind(lambda, base::Unretained(this), &event);net_test_task_runner_->PostTask(std::move(callback));event.Wait();}This result in a lot of "self->" and forces public members (currently that test happens to use a lot of protected method for testing -- perhaps a bad paradigm on its own but one I was trying to avoid addressing).
Neither of these seem particularly painful to me. Do they do you?Yes. In isolation they're not bad but if this becomes the recommended paradigm to write tests as more things are sequenced it will be cumbersome and make our "my codebase doesn't have unnecessary complexity" even worse IMO.
I just thought of a third-way which would be fairly nice:// Returns an object in whose scope executed code is seen as running in// this TestMockTimeTaskRunner's context (i.e. ThreadTaskRunnerHandle, RunsTasksOnCurrentThread, etc.).std::unique_ptr<TestMockTimeTaskRunner::Context> TestMockTimeTaskRunner::EnterRuntimeContext();Then I can do what I want (run synchronously in the scope of that task runner without having to jump through hoops) -- this is actually even cleaner than bind lambda+RunUntilIdle().I'll go ahead and implement this.
2. Bind the lambda without this.TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) {auto lambda = [](HttpServerPropertiesManagerTest* self, WaitableEvent* event) {// Move all the test code here.. and use public instead of private members.event->Signal();}WaitableEvent event;auto callback = base::Bind(lambda, base::Unretained(this), &event);net_test_task_runner_->PostTask(std::move(callback));event.Wait();}This result in a lot of "self->" and forces public members (currently that test happens to use a lot of protected method for testing -- perhaps a bad paradigm on its own but one I was trying to avoid addressing).This isn't my favorite either because of all the self->, but making protected methods public in a test harness seems pretty okay.
Neither of these seem particularly painful to me. Do they do you?Yes. In isolation they're not bad but if this becomes the recommended paradigm to write tests as more things are sequenced it will be cumbersome and make our "my codebase doesn't have unnecessary complexity" even worse IMO.I guess I don't agree that these equate to complexity, considering the proposal was to move the body of the test onto another thread, and the complexity that implies.
I just thought of a third-way which would be fairly nice:// Returns an object in whose scope executed code is seen as running in// this TestMockTimeTaskRunner's context (i.e. ThreadTaskRunnerHandle, RunsTasksOnCurrentThread, etc.).std::unique_ptr<TestMockTimeTaskRunner::Context> TestMockTimeTaskRunner::EnterRuntimeContext();Then I can do what I want (run synchronously in the scope of that task runner without having to jump through hoops) -- this is actually even cleaner than bind lambda+RunUntilIdle().I'll go ahead and implement this.But I'm glad you've got another solution. In this case it's avoiding the use of posting a method then?