-
-
Notifications
You must be signed in to change notification settings - Fork 525
generators: Auto extract cases #568
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
Conversation
lib/generator/template_values.rb
Outdated
@@ -31,8 +31,40 @@ def cases_require_name | |||
Files::GeneratorCases.filename(exercise_name) | |||
end | |||
|
|||
def test_cases |
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.
There is a LOT of untested logic here. That scares me.
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.
Me too!
lib/generator/template_values.rb
Outdated
end | ||
|
||
def test_cases_proc? | ||
Object.const_defined?(test_cases_procname) |
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.
Use the method you already have: test_cases_proc.exists?
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.
test_cases_proc
returns NameError
if the constant is not defined. I dislike rescuing an error in this situation, but would prefer to check to see if it is there.
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 was desirable before, for the whole thing to blow up if the test case class did not exist. Since that's no longer the case it suggests to me that test_cases_proc
needs changing to something like:
def test_cases_proc
Object.const_get(test_cases_procname) if Object.const_defined?(test_cases_procname)
end
(This may be moot due to upcoming object extraction.)
@@ -25,6 +25,10 @@ def test_filename | |||
assert_equal 'two_parter_cases', GeneratorCases.filename(exercise_name) | |||
end | |||
|
|||
def test_class_name | |||
assert_equal 'TwoParterCase', GeneratorCases.class_name('two-parter') | |||
end |
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 is a nice test
lib/generator/files/track_files.rb
Outdated
def proc_name(exercise_name) | ||
filename(exercise_name).split('_').map(&:capitalize).join | ||
"#{class_name(exercise_name)}s" |
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 you're just adding an 's' do class_name(exercise_name) + 's'
I'd like to see an example of how |
lib/generator/template_values.rb
Outdated
test_cases_proc.call(canonical_data.to_s) | ||
else | ||
test_cases_with_index | ||
end |
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.
There's another object hiding in here.
Replace all this with:
test_cases_foobar.call(canonical_data.to_s)
Then work out what test_cases_foobar is.
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 will also help solve your (my) "bunch of untested private methods" problem.
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.
💯 Win, win, win. I'll refactor and dig that object out tomorrow.
|
lib/generator/template_values.rb
Outdated
end | ||
|
||
def test_case_class | ||
Object.const_get(Files::GeneratorCases.class_name(exercise_name)) |
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.
@Insti here is where class_name
is used.
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.
So proc_name
is never used externally and should be private
?
I read the comment above.
Refactoring to split apart the adapter and the two solutions |
simple_canonical_data | ||
end | ||
|
||
def complex_canonical_data |
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.
These (simple|complex) can live in /fixtures
somewhere.
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.
We discussed this in gitter and have decided to try a data section at the end of the test file.
The main thing is removing the big heredoc from the middle of the test file.
|
||
class CaseValuesTest < Minitest::Test | ||
def setup | ||
$LOAD_PATH.unshift 'test/fixtures/xruby/lib' |
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.
Modifying the load path for every test should not be necessary.
But there might be something else to do so that everything still works.
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 was following the existing pattern.
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 probably should fix that then 😊
end | ||
|
||
def simple_canonical_data | ||
simple_canonical_data = Minitest::Mock.new |
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.
Why is this a Mock
?
Nevermind.
complex_canonical_data = Minitest::Mock.new | ||
complex_canonical_data.expect( | ||
:to_s, | ||
<<-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.
Were you going to move this data out of the tests?
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.
They're at the bottom of the file now.
Where I'd really like to put these is in a module I could include.
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.
In which case why not use a fixture?
How is a module any different, or even preferable when the data should be non-executable?
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.
A module can easily be included in multiple places, but (may be/is ?) easier to be surgical than a fixture.
I guess the question is, what are you suggesting? That I create fixtures for each of these cases, in which case I will end up duplicating data or reusing fixtures across tests, neither of which is desirable.
While data is non-executable, being able to manipulate the data via code makes the test suite far more manageable.
@@ -0,0 +1,116 @@ | |||
require_relative '../test_helper' |
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.
case_values_auto_extractor_test.rb
has too many _auto_extractor
s in the filename
@@ -56,4 +56,5 @@ def teardown | |||
$LOAD_PATH.delete 'test/fixtures/xruby/lib' | |||
end | |||
end | |||
|
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.
An unnecessary blank line change has snuck in.
$LOAD_PATH.unshift 'test/fixtures/xruby/lib' | ||
end | ||
|
||
def test_simple_auto_extraction |
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 believe this test is redundant.
Just load the alpha_cases file direcly, we know where it is.
test/fixtures/metadata/exercises/alpha/canonical-data.json We are the only user of this fixture data.
Renamed 'gamma' to 'complex'.
Add test that template_values loads problem cases Remove commented out code. Make everything that loads AlphaCase(s) clean up after itself. Undefine AlphaCase(s) during teardown. Remove redundant setup. Check for both classes. Add tests for class based test generation squash Remove TODO comment
9a14c4d
to
45511ff
Compare
all generators converted to use auto extraction in exercism#567
(We're not making use of it yet, but now it is there we can.)
Refactor Extractor
Motivation and Context
While working on #566, I noticed that a number of the existing generators would not run because the loop which extracts cases from the data did not match the current structure. I also noticed a lot of consistency in the loops for both failing and successful generators. Automatically extracting cases from the JSON feels like a big win.
Description
Added
Generator::CaseValues
(inlib/generator/case_values.rb
, which extracts the cases from the canonical data. It uses a custom extractor if such an extractor exists, otherwise it extracts the cases automagically.How Has This Been Tested?
Generator::CaseValues
for both custom extractor and not custom extractor and for both simple and complex canonical data.Generator::Files::GeneratorCases
.Types of changes
No breaking changes.
New feature: auto extraction of cases.
References and Closures
Checklist:
My change relies on a pending issue/pull request