emacs-buttercup
emacs-buttercup copied to clipboard
WIP: Add support for capturing dynamic binding environment
Fixes #127, kind of.
This is quite a bit of black magic and I'm using eval, however I can't really find any other way.
Without using :env
it falls back to the old code so this should not affect any current usage.
A simple test case
(describe "env test"
:env ((kill-ring kill-ring))
(it "should capture environment"
(with-temp-buffer
(insert "asdasd")
(goto-char (point-min))
(kill-line))
(expect kill-ring :to-equal (list "asdasd")))
(it "should restore environment"
(expect kill-ring :to-be nil)))
without the :env
flag the second test fails as it is polluted by the first one doing the killing.
Thank you for the PR. Wouldn't it be easier and more readable to just setq
the variable in before-each
, or maybe just support an around-each
type of thing?
@jorgenschaefer Problem with setq
is that it corrupts the global state. It would not be a problem if buttercup run each test case in a separate Emacs instance but that would be crazy slow.
It might work for one describe
set if I always initialize it but basically it would force me to do it absolutely everywhere in the entire test suite. For example, imagine I set case-fold-search
to nil
in one suite, then for the rest of the execution it is going to have this value.
What can be done with the around-each
would be to get the value and then re-set it which would work but we must take care of errors also (i.e. never forget to re-set the value). The user would have to do this manually for every variable then. This is basically what this PR does.
Theoretically, this might work
(describe "Backup"
:var (kill-ring-backup)
(before-each
(setq kill-ring-backup kill-ring)
(setq kill-ring ("foobar")))
(after-each
(setq kill-ring kill-ring-backup))
(it "kill ring should not be empty"
(expect (< 0 (length kill-ring)) :to-be-truthy)))
Then the question is what are the guarantees on after-each
.
What you described is a common idiom in javascript but remember that there the scoping works different
describe('getProductValue', () => {
let edsnDown
describe('when edsn is up', () => {
beforeEach(() => {
edsnDown = false
})
it("should return '1' when we have elk only", () => {
expect(getProductValue(true, edsnDown)).toEqual('1')
})
it("should return '2' when we have elk and gas", () => {
expect(getProductValue(false, edsnDown)).toEqual('2')
})
})
})
here the edsnDown
will never spill outside of the describe... in Emacs special variables will :(
How about around
?
(describe "Backup"
(around-each block
(let ((kill-ring '("foobar")))
(funcall block)))
(it "kill ring should not be empty"
(expect (< 0 (length kill-ring)) :to-be-truthy)))
@jorgenschaefer That is actually really cool idea. You were doing some ruby lately heh? :D
Yea I think that could work if implemented properly. I'll try to take a look on that if you don't mind (or have it already implemented)
Am I getting a Ruby dialect? Help! :-D I have nothing implemented and I would love such a feature, thank you!
@Fuco1 Great work so far with this! Looking forward to its completion!
P.S. As a Rubyist myself I welcome any suggestion to get buttercup closer to what RSpec offers - it's a pretty amazing framework.
Is there any progress on this? This is quite an important feature missing in buttercup. Without it, "mocking" special variables becomes quite annoying.
I probably won't work on this in any reasonably close future.
This PR is probably older than my maintainership, and as it was marked WIP I never gave it much thought.
I don't think I'll get to it soon considering how little time I have to spend on this project.
If you have any specific problem, please file a separate issue. Maybe we can figure something out.