all-your-base: add test generator#510
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. |
| input_base = 2 | ||
| output_base = 10 | ||
| expected = [] | ||
| expected = WHAT TO DO? |
| input_base = 10 | ||
| output_base = 2 | ||
| expected = [0] | ||
| expected = WHAT TO DO? |
| input_base = 10 | ||
| output_base = 2 | ||
| expected = [0] | ||
| expected = WHAT TO DO? |
| input_base = 2 | ||
| output_base = 10 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid input
There was a problem hiding this comment.
Currently we just expect the output to be nil. Should the cases with invalid data be changed to expect an error to be raised?
| input_base = 7 | ||
| output_base = 10 | ||
| expected = [4, 2] | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
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!
| input_base = 2 | ||
| output_base = 10 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid input
| input_base = 1 | ||
| output_base = 10 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| input_base = 2 | ||
| output_base = 1 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
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.
| input_base = 0 | ||
| output_base = 10 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| input_base = 10 | ||
| output_base = 0 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| input_base = -2 | ||
| output_base = 10 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| input_base = 2 | ||
| output_base = -7 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| input_base = -2 | ||
| output_base = -7 | ||
| expected = nil | ||
| expected = WHAT TO DO? |
There was a problem hiding this comment.
raise error about invalid base.
| @@ -1,9 +1,10 @@ | |||
| gem 'minitest', '>= 5.0.0' | |||
|
Hmm. The reason the checks are failing is because, without specifying the Adding: AllCops:
TargetRubyVersion: 2.1solves 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.
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.
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.
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.
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.
Bumped test version since we now expect invalid base / input to raise an error rather than return nil
| 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.
I tried to change as little as possible here to get tests to pass. Does this look okay?
|
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.
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.
Completely agreed.
Would text or code be better, maybe?
There was a problem hiding this comment.
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.
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.
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. |
|
|
||
| private :row | ||
| private | ||
|
|
There was a problem hiding this comment.
Why not:
private
attr_reader :rowMove the private things past the private declaration... Leaving call above that line.
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
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.
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.
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
Insti
left a comment
There was a problem hiding this comment.
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-baseto 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!