-
-
Notifications
You must be signed in to change notification settings - Fork 525
grains: add test generator #514
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
module Grains | ||
def self.square(number) | ||
fail ArgumentError if number <= 0 || number > 64 |
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 had to make an adjustment to the implementation because the shared test data includes some error cases that weren't in the original ruby implementation.
How does this work with book keeping when it wasn't there originally? Normally, I'm assuming we would bump the BookKeeping::VERSION
, but this exercise wasn't using book keeping yet.
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.
The adjustment looks reasonable.
BookKeeping is related to the tests, so you might need to add it in so that the example.rb still passes the tests.
2**(number - 1) | ||
end | ||
|
||
def self.total | ||
square(65) - 1 | ||
2**64 - 1 |
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.
Because of the change to the square method, calling square(65)
would raise an ArgumentError
, so I just made the smallest change possible to make the tests pass. Is this okay?
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 fine.
skip | ||
assert_equal 32_768, Grains.square(16) | ||
assert_equal 32768, Grains.square(16) |
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 elected to use the32769
notation rather than 32_768
for simplicities sake. Is this okay, or should I update it to use the other notation?
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 fine.
Although supporting the underscore version should just require a simple helper method.
skip | ||
assert_equal 9_223_372_036_854_775_808, Grains.square(64) | ||
assert_equal 9223372036854775808, Grains.square(64) |
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.
When we get to numbers like this the underscore representation is REALLY helpful.
input: row['input'], | ||
) | ||
|
||
GrainsCase.new(row.merge('assertion' => assertion, 'index' => i)) |
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.
Rather than constructing a GrainsCase
here, how about subclassing it and just doing
GrainsCase::SquareMethod.new(row: row, index: i)
GrainsCase.new(row.merge('assertion' => assertion, 'index' => i)) | ||
end | ||
|
||
assertion = GrainsCase::TotalAssertion.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 does this look different to the square
method code?
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 because of the format of the canonical data:
{
"square": {
"cases": [
{ "description": "...", "input": 1, "expected": 1 },
...
]
},
"total": {
"description": "...",
"expected": "..."
}
}
Sorry my review pace has slowed down, the holidays seem to leave me with less time rather than more!. I've still got my eye on these PRs, I'm just trying to find some time to give them a final test/review before merging them. |
@Insti No problem at all! I totally understand 😄 |
GrainsCase::SquareMethod.new(row.merge('index' => i)) | ||
end | ||
|
||
cases << GrainsCase::TotalMethod.new(data['total']) |
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 case doesn't know its index
.
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.
btw: This looks much nicer than it did last time I looked at it.
private | ||
|
||
def error_assertion | ||
"assert_raises(ArgumentError) { Grains.square(#{input}) }" |
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.
dodgy indentation.
private | ||
|
||
def formatted_expected | ||
expected.to_s.reverse.gsub(/...(?=.)/,'\&_').reverse |
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 would be nicer as a function that took an argument.
def underscore_format(number)
Then you use it as: underscore_format(expected)
@@ -0,0 +1,87 @@ | |||
require_relative 'test_helper' | |||
|
|||
class GrainsTest < Minitest::Test |
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 really like that you're unit testing the Case
classes. 👍
Hopefully doing this will help you realise which methods should be part of some kind of BaseCase
class that could be inherited from rather than always starting from OpenStruct
assert_equal '# skip', GrainsCase.new(index: 0).skipped | ||
end | ||
|
||
def test_skipped_with_nil_index |
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.
Should a case ever have a nil
index?
What is the point of an index?
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 little bit of a tricky one that I'm not sure on the best way to handle.
In my (limited) experience, when the canonical data has more than one "type" of test case, they both each follow the same JSON structure (e.g. allergies). This lets you do something like this when assembling the cases (not an optimal solution necessarily, just demonstrating):
i = -1
JSON.parse(data).flat_map do |type, test_data|
test_data['cases'].map do |test_case|
i += 1
# Determine which kind of Case to make based on type
Case.new(...)
end
end
But in this case the JSON is structured like:
{
"square": {
"cases": [
{ "description": "...", "input": 1, "expected": 1 },
...
]
},
"total": {
"description": "...",
"expected": "..."
}
}
Because of this, I'm not too sure how to get a real index for this case.
Do you have any thoughts on this? Would it be better to explicitly pass index: false
for that case? It's still pretty strange though 😞
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 does the index
represent? What is it the index of?
Does it mean different things in different places?
(I know the answer, I'm just trying to help you get there.)
(index: false
is not the correct answer)
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's the index of the set of test cases. Would something like this work:
data = JSON.parse(data)
i = -1
cases = data['square']['cases'].map do |row|
i += 1
GrainsCase::SquareMethod.new(row.merge('index' => i))
end
cases << GrainsCase::TotalMethod.new(data['total'], index: i+1)
It adds a bit of complexity, but at least the index is correct.
Thank you so much for your help and feedback!
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.
Getting closer 😄
In the above example, how does i
relate to cases.size
?
883d1f9
to
577fa7e
Compare
577fa7e
to
b3e62ca
Compare
Is this ready to merge? |
As far as I'm concerned, this should be good to go 😄 If there are any other changes you all would like to see, I'm happy to keep working at it! |
Thanks for all your work on this @tommyschaefer ❤️ |
Hi there!
Checking off exercises from #396.
I tried to include tests for the generator this time around. Is this okay? If so, should I add a
cases
(or another name) test directory to group the tests? Or is it okay as it is?I also had a couple other questions, but I'll add them as comments on specific lines.
Thank you so much for your time!