-
-
Notifications
You must be signed in to change notification settings - Fork 525
all-your-base: add test generator #510
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
Works in progress are definitely encouraged. |
You'll need to pre-process the canonical data and define the appropriate values. The existing all-your-base example solution should give you an indication of what the appropriate values are. |
@@ -119,7 +123,7 @@ def test_empty_list | |||
digits = [] | |||
input_base = 2 | |||
output_base = 10 | |||
expected = [] | |||
expected = WHAT TO DO? |
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.
expected = []
output_base = 2 | ||
expected = [0] | ||
expected = WHAT TO DO? |
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.
expected = [0]
output_base = 2 | ||
expected = [0] | ||
expected = WHAT TO DO? |
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.
expected = [0]
@@ -175,7 +179,7 @@ def test_negative_digit | |||
digits = [1, -1, 1, 0, 1, 0] | |||
input_base = 2 | |||
output_base = 10 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid 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.
Currently we just expect the output to be nil. Should the cases with invalid data be changed to expect an error to be raised?
@@ -161,7 +165,7 @@ def test_leading_zeros | |||
digits = [0, 6, 0] | |||
input_base = 7 | |||
output_base = 10 | |||
expected = [4, 2] | |||
expected = WHAT TO DO? |
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.
expected = [4, 2]
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.
After looking at it with some fresh eyes, I think this is the only example that I'll have trouble implementing.
For the other examples I can check whether their input and bases are valid and generate a test on that. Also the empty / 0 input cases shouldn't be hard to catch either.
Because we ignore leading zeros in the input, the expected output for the given inputs is not included in the shared test data. I'm not sure how to handle this case in a way that would allow the input or bases to change without new generations breaking. Do you have any ideas on this one?
Thank you so much for your help and time!
@@ -189,7 +193,7 @@ def test_invalid_positive_digit | |||
digits = [1, 2, 1, 0, 1, 0] | |||
input_base = 2 | |||
output_base = 10 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid input
@@ -203,7 +207,7 @@ def test_first_base_is_one | |||
digits = [] | |||
input_base = 1 | |||
output_base = 10 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -217,7 +221,7 @@ def test_second_base_is_one | |||
digits = [1, 0, 1, 0, 1, 0] | |||
input_base = 2 | |||
output_base = 1 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
probably raise an error about invalid base.
I'd like to see a base 1 representation: [1] * 42 but that is not consistent with everything else.
@@ -231,7 +235,7 @@ def test_first_base_is_zero | |||
digits = [] | |||
input_base = 0 | |||
output_base = 10 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -245,7 +249,7 @@ def test_second_base_is_zero | |||
digits = [7] | |||
input_base = 10 | |||
output_base = 0 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -259,7 +263,7 @@ def test_first_base_is_negative | |||
digits = [1] | |||
input_base = -2 | |||
output_base = 10 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -273,7 +277,7 @@ def test_second_base_is_negative | |||
digits = [1] | |||
input_base = 2 | |||
output_base = -7 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -287,7 +291,7 @@ def test_both_bases_are_negative | |||
digits = [1] | |||
input_base = -2 | |||
output_base = -7 | |||
expected = nil | |||
expected = WHAT TO DO? |
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.
raise error about invalid base.
@@ -1,9 +1,10 @@ | |||
gem 'minitest', '>= 5.0.0' |
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 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.
yes. remove this line.
Hmm. The reason the checks are failing is because, without specifying the Adding: AllCops:
TargetRubyVersion: 2.1 solves this problem. Should I open an issue / PR for discussing that change, or should I include it in this PR? |
Doing this as a separate PR would be great, thanks. |
@@ -1,4 +1,8 @@ | |||
class AllYourBaseCase < OpenStruct | |||
def self.build(row:, index:) | |||
new(PreProcessor.new(row: row, index: index).run) |
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.
You can get rid of this method completely by just calling the preprocessor directly on line 89
attr_reader :row, :index | ||
|
||
def expected_value | ||
return row['expected'] unless row['expected'].nil? |
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 headed in the right direction.
An alternate method would be to special case each one based on the description (or the input values.)
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.
Which do you prefer?
Personally, I like the fact that it's resilient to the test data changing how it is, but I can go both ways. It does feel a bit strange that some of the exercise logic is reproduced in the generator, 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.
return row['expected'] if row['expected']
Just realized a couple comments were in outdated diffs, so I'll repost them here for visibility. One was:
The second was regarding the test for leading zeros:
|
696a63a
to
49d4b75
Compare
Hmm... sorry. I unfortunately messed up the rebase ⬆️ Should be fixed now though. |
Yes these should raise an error.
Hardcoding values in the pre-processor is acceptable. Changes to the canonical-data are allowed to break the test generation. |
@@ -1,17 +1,22 @@ | |||
module BookKeeping | |||
VERSION = 1 | |||
VERSION = 2 |
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.
Bumped test version since we now expect invalid base / input to raise an error rather than return nil
end | ||
|
||
class BaseConverter | ||
def self.convert(base_from, number_array, base_to) | ||
return if number_array.any?{|number| number < 0 || number >= base_from} | ||
return if base_from <= 1 || base_to <= 1 | ||
fail ArgumentError if invalid_inputs?(base_from, number_array, base_to) |
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 tried to change as little as possible here to get tests to pass. Does this look 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.
that's fine.
This looks good @tommyschaefer. |
72f3911
to
9c785ee
Compare
lines.split("\n").map do |line| | ||
' ' * size + line | ||
end.join("\n") | ||
lines.lines.each_with_object('') { |line, obj| obj << ' ' * size + line } |
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.
lines.lines
looks weird.
If you need to call lines
on it that suggests to me that it's not lines at all, so either needs to be lines that get passed in or needs a different 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.
Completely agreed.
Would text
or code
be better, maybe?
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 have a slight preference for text
but it doesn't make too much difference.
"", | ||
indent(4, "assert_raises ArgumentError do"), | ||
indent(6, "BaseConverter.convert(input_base, digits, output_base)"), | ||
indent(4, "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.
One thing that bugs me about this otherwise great solution is all the micro-management of indentation that is going on. (It's not just in this method, but throughout the whole class.)
There must be a more elegant way of handling it.
4a788a3
to
af01f6c
Compare
af01f6c
to
e9d07a7
Compare
Is there anything more than needs to be done here? (@tommyschaefer you should come to the Gitter chat room: https://gitter.im/exercism/xruby) |
As far as I'm concerned, I don't have anything else to add 😄 If there are any other changes you all would like to see, I'm happy to keep working at it! |
I noticed this in the travis log:
|
I guess one thing to mention is that this generator isn't tested. Is that something you would like to see happen before thinking about bringing these changes in? |
@Insti nice catch! I'll look into it 😄 |
|
||
private | ||
|
||
attr_reader :row |
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.
Hmm looks like the warning in Travis is coming from this line.
You're welcome to add them if you want, but I'd be fine bringing it in without tests.
|
This change is to remove a warning present in ruby versions less than 2.3.0. A thread discussing this warning can be found at https://bugs.ruby-lang.org/issues/10967. It is removed in ruby/ruby@32a5a09.
Sounds good. We can move forward without them as far as I'm concerned. I'll circle back around to these once the new generator stuff gets added. Is it okay if I add an issue to remember this? |
Yep. That's one of the things they're for. |
def call(row) | ||
@row = row | ||
|
||
row.merge('expected' => expected_value) | ||
end | ||
|
||
private :row | ||
private | ||
|
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 not:
private
attr_reader :row
Move the private things past the private
declaration... Leaving call
above that line.
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 what we were chatting about on Gitter the other day.
In ruby < 2.3.0 private reader methods made like that cause a warning. In 2.3 that warning is removed. Links to some info about this are in the last commit message.
Thanks for the 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.
This is the last commit, and instead of moving the line, one more line was created.
If you move the attr_reader to below the private line, there is no warning for 2.4 (in regards to that) that I am finding.
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 warning was removed in ruby 2.3, so in all later versions it isn't there and you won't see it in 2.4. Since we use 2.1.2, it shows up in CI and whatnot.
I'm not sure if moving the reader under private but keeping the explicit private with method name will still make a warning. I'll give this a try when I'm home.
Sorry for the lack of code samples... aparently the iOS keyboard doesn't have a back tick key? 😞
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.
Copying commit message here so it can be read inline:
This change is to remove a warning present in ruby versions
less than 2.3.0. A thread discussing this warning can be found
at https://bugs.ruby-lang.org/issues/10967. It is removed in
ruby/ruby@32a5a09.
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.
Yeah, that's what I had originally but it's what causes the warning mentioned above. Ruby versions less than 2.3.0 have a warning when a private attribute is defined unless its made private explicitly with private :method_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.
As it is a warning, and not functionally wrong, I would probably leave it at that. This also means as time goes on and the version of Ruby moves forward, it will eventually take care of itself.
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'd prefer that the code not emit warnings. If that means temporarily doing some sub-optimal things to keep the interpreter happy then so be it.
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.
Definitely prefer warning free. How will we trigger when it should be "corrected" when the warning would naturally go away? Not that it is an important change...
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 don't think it needs an explicit trigger. Next time that code gets edited, whoever modifies it will think it looks wrong, (unjustly) curse @tommyschaefer for being an idiot 😜 and fix it.
Also, the private call was ineffective.
Update all-your-base example to use more idiomatic ruby
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'm happy this is ready to go.
Thanks for all your work on this @tommyschaefer ❤️ |
Hi there!
Checking off exercises from #396.
I've made some good progress converting
all-your-base
to use generated tests, but I've run into a bit of a snag implementing the 13 undefined tests from the shared data.I've opened exercism/problem-specifications#473 to see if this has been solved before, or if some new information will have to be added to the shared test data.
In the future, would it be preferable for me to wait to make a PR until the changes are fully ready for review? I was thinking it may be better to just go ahead and make the PR so that people could see it had some work being done on it, but if thats not the case I won't do it in the future 😄!
Thank you so much for your time!