Clearer errors in 1.9's minitest

Hello!

I've been getting back into Ruby, and one of the major changes I've
made is to switch to 1.9 and to strictly use tests. I'm using the
minitest[1] in 1.9 (via rvm[2])

It's nice, and I'm pleased at what I've been able to accomplish with
its help.

However, it's been long enough that one issue has pissed me off
to no end and I need some advice on it. I'm not sure how to describe
what I'm looking for concisely enough to search for it effectively, so
I thought I'd sign up and ask.

When an error is caught, its output is not as helpful as I wish it to
be.

Example script:

···

----------
require 'minitest/autorun'

class Test_Markup < MiniTest::Unit::TestCase

  def test()
    assert_equal(
      ( 'asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ' ),
      ( 'qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ' ),
    )
  end

end
----------

Example output:

----------
Loaded suite /foo/bar/baz.rb
Started
F
Finished in 0.000440 seconds.

  1) Failure:
test(Test_Markup)
  [/foo/bar/baz.rb:7]:
  Expected "asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ", not
  "qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ".

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 48126
----------

The "expected/not" text is not nearly as helpful to me as it
could/should be. It forces me to

- copy/paste it to a text file
- shove the text around to "line it up"
- comb through it character-by-character for differences
- slowly go insane(r)

What I instead want is to have a coloured side-by-side comparison
similar to a decent diff.

Is this possible within minitest as it stands currently? Has anyone
else done this already, perhaps with other libraries/tools?

How challenging would this be to implement? If there were some way for
me to "get at" that text, I could use existing and very mature external
tools to do exactly what I want. e.g. if I were given one big array
with sub-arrays, within which is all the error information.. then I
could do some real magic.

I'd really rather not use an alternative to minitest, mostly because
the syntax used in them makes me want to scoop my brain out with a
teaspoon.

Point me to websites, documentation or source code. Any and all help
is appreciated.

---

[1] http://bfts.rubyforge.org/minitest/
[2] http://rvm.beginrescueend.com/rvm/

--

http://spiralofhope.com

Wall of text hits you for 99,999 hp.
You die!

Hello!

I've been getting back into Ruby, and one of the major changes I've
made is to switch to 1.9 and to strictly use tests. I'm using the
minitest[1] in 1.9 (via rvm[2])

It's nice, and I'm pleased at what I've been able to accomplish with
its help.

However, it's been long enough that one issue has pissed me off
to no end and I need some advice on it. I'm not sure how to describe
what I'm looking for concisely enough to search for it effectively, so
I thought I'd sign up and ask.

When an error is caught, its output is not as helpful as I wish it to
be.

Example script:

----------
require 'minitest/autorun'

class Test_Markup < MiniTest::Unit::TestCase

def test()
   assert_equal(
     ( 'asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ' ),
     ( 'qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ' ),
   )
end

end

You don't actually write your code that way, do you?

Example output: [...]

How challenging would this be to implement? If there were some way for
me to "get at" that text, I could use existing and very mature external
tools to do exactly what I want. e.g. if I were given one big array
with sub-arrays, within which is all the error information.. then I
could do some real magic.

I'd really rather not use an alternative to minitest, mostly because
the syntax used in them makes me want to scoop my brain out with a
teaspoon.

Point me to websites, documentation or source code. Any and all help
is appreciated.

You already have the source code. Have you read it? It is called minitest for a reason. Dig in.

% ./x.rb
Run options: --seed 34017

# Running tests:

F

Finished tests in 0.000610s, 1639.3443 tests/s, 1639.3443 assertions/s.

  1) Failure:
test_example(TestMarkup) [./x.rb:8]:
Expected "asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl ", not "qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop ".

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

versus:

···

On Mar 25, 2011, at 21:13 , spiralofhope wrote:

% sudo gem install ZenTest
% ./x.rb | unit_diff -u
Run options: --seed 4937
# Running tests:

F

Finished tests in 0.000641s, 1560.0624 tests/s, 1560.0624 assertions/s.

Run options: --seed 4937

1) Failure:
test_example(TestMarkup) [./x.rb:8]:
--- /var/folders/x-/x-z1ojKcE+CpI1+qvSPWTk+++TU/-Tmp-/expect20110326-21801-yrc96l-0 2011-03-26 13:11:21.000000000 -0700
+++ /var/folders/x-/x-z1ojKcE+CpI1+qvSPWTk+++TU/-Tmp-/butwas20110326-21801-zn2uft-0 2011-03-26 13:11:21.000000000 -0700
@@ -1 +1 @@
-"asdfghjkl asdfghjkl asdfghjkl asdfghjkl asdfghjkl "
+"qwertyuiop qwertyuiop qwertyuiop qwertyuiop qwertyuiop "

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

You don't actually write your code that way, do you?

I'm assuming you're commenting on my general style. Moved to another
thread. CCed you.

% sudo gem install ZenTest
% ./x.rb | unit_diff -u

Interesting. I played with this and it's not quite what I'm looking
for, but it's nice to have that in my toolkit. Thanks.

You already have the source code. Have you read it? It is called
minitest for a reason. Dig in.

I hadn't read it. Most source is pretty intimidating at my current
skill level.

I did just now take a look around and I think I found what I'm looking
for.

~/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/minitest/unit.rb

The assert_equal method, and possibly even mu_pp are the two places
I think I could use.

I did some initial playing and the results are already vastly more
readable to me. I'm a bit surprised I was able to do this. Thanks for
the motivation.

···

On Sun, 27 Mar 2011 05:12:51 +0900 Ryan Davis <ryand-ruby@zenspider.com> wrote:

--
http://spiralofhope.com

More or less. I'm assuming you're commenting on my general style.
Below would be a full working bit of code. It's rather pointlessly
simple but it demonstrates my "way".

···

On Sun, 27 Mar 2011 05:12:51 +0900 Ryan Davis <ryand-ruby@zenspider.com> wrote:

You don't actually write your code that way, do you?

---
require 'minitest/autorun'

class Whatever

  def foo( string )
    return string + '!'
  end

end

class Test_Whatever < MiniTest::Unit::TestCase

  def setup()
    @o = Whatever.new
  end

  def test_foo()
    assert_equal(
      ( 'yay!' ),
      ( @o.foo( 'yay' ) ),
    )
  end

end
---

I've taken extreme measures to make my code more readable. While I
have exceptionally lucid times, I often have a _very_ hard time
"fitting a program into my head".

The real problem arises when I create magical code on one day and then
on some other day I am completely unable to comprehend it.

To help, I've been

- Breaking my problems down into sometimes embarrassingly-small pieces
- .. Each with its own test
- .. Usually with somewhat redundant comments.
- I've also thrown away regular alignment conventions.
- Ignoring performance improvements, preferring clearer and even
  redundant code. (lots of brackets, stuff on separate lines, trailing
  commas, etc)
- Using a very small subset of Ruby's functionality. Doing things with
  brute force and which are far less pretty than possible.

In some cases I might even coerce code into something monstrous like
this:

  def test_foo()
    assert_equal(
              ( 'yay!' ),
      ( @o.foo( 'yay' ) ),
    )
  end

The difference to me is that a bunch of programming that initially took
me a very long time has now taken me a very short time to rewrite from
scratch. Think years to weeks. The end result is vastly superior in
every way to me. Faster, clearer, fully tested. Most importantly I'm
enjoying myself!

I know that this means that if I ever manage to function with regular
style conventions I will be forced to re-rewrite everything to follow
them. If it came to that, I would be pleased to do it.. I love that
kind of grunt work. =)

I know I'm learning bad habits, my code will be "unreadable" to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues.. but I needed a new way to approach
programming. It's either that or I just give up.

--
http://spiralofhope.com

I know I'm learning bad habits, my code will be "unreadable" to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues.. but I needed a new way to approach
programming. It's either that or I just give up.

That's fine, but then what is the point of this post? Are you asking for
help with integrating yourself into more of the semantics of the Ruby Style
way of coding? I guess I'm missing something.

-Nick Klauer

···

On Sat, Mar 26, 2011 at 19:33, spiralofhope <spiralofhope_rubyml@lavabit.com > wrote:

On Sun, 27 Mar 2011 05:12:51 +0900 > Ryan Davis <ryand-ruby@zenspider.com> wrote:

> You don't actually write your code that way, do you?

More or less. I'm assuming you're commenting on my general style.
Below would be a full working bit of code. It's rather pointlessly
simple but it demonstrates my "way".

---
require 'minitest/autorun'

class Whatever

def foo( string )
   return string + '!'
end

end

class Test_Whatever < MiniTest::Unit::TestCase

def setup()
   @o = Whatever.new
end

def test_foo()
   assert_equal(
     ( 'yay!' ),
     ( @o.foo( 'yay' ) ),
   )
end

end
---

I've taken extreme measures to make my code more readable. While I
have exceptionally lucid times, I often have a _very_ hard time
"fitting a program into my head".

The real problem arises when I create magical code on one day and then
on some other day I am completely unable to comprehend it.

To help, I've been

- Breaking my problems down into sometimes embarrassingly-small pieces
- .. Each with its own test
- .. Usually with somewhat redundant comments.
- I've also thrown away regular alignment conventions.
- Ignoring performance improvements, preferring clearer and even
redundant code. (lots of brackets, stuff on separate lines, trailing
commas, etc)
- Using a very small subset of Ruby's functionality. Doing things with
brute force and which are far less pretty than possible.

In some cases I might even coerce code into something monstrous like
this:

def test_foo()
   assert_equal(
             ( 'yay!' ),
     ( @o.foo( 'yay' ) ),
   )
end

The difference to me is that a bunch of programming that initially took
me a very long time has now taken me a very short time to rewrite from
scratch. Think years to weeks. The end result is vastly superior in
every way to me. Faster, clearer, fully tested. Most importantly I'm
enjoying myself!

I know that this means that if I ever manage to function with regular
style conventions I will be forced to re-rewrite everything to follow
them. If it came to that, I would be pleased to do it.. I love that
kind of grunt work. =)

I know I'm learning bad habits, my code will be "unreadable" to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues.. but I needed a new way to approach
programming. It's either that or I just give up.

--
http://spiralofhope.com

*Spiral,*

spiralofhope wrote:

You don't actually write your code that way, do you?
     

More or less. I'm assuming you're commenting on my general style.
Below would be a full working bit of code. It's rather pointlessly
simple but it demonstrates my "way".

---
require 'minitest/autorun'

class Whatever

   def foo( string )
     return string + '!'
   end

end

class Test_Whatever< MiniTest::Unit::TestCase

   def setup()
     @o = Whatever.new
   end

   def test_foo()
     assert_equal(
       ( 'yay!' ),
       ( @o.foo( 'yay' ) ),
     )
   end

end
---

I've taken extreme measures to make my code more readable. While I
have exceptionally lucid times, I often have a _very_ hard time
"fitting a program into my head".

The real problem arises when I create magical code on one day and then
on some other day I am completely unable to comprehend it.

To help, I've been

- Breaking my problems down into sometimes embarrassingly-small pieces
- .. Each with its own test
- .. Usually with somewhat redundant comments.
- I've also thrown away regular alignment conventions.
- Ignoring performance improvements, preferring clearer and even
   redundant code. (lots of brackets, stuff on separate lines, trailing
   commas, etc)
- Using a very small subset of Ruby's functionality. Doing things with
   brute force and which are far less pretty than possible.

In some cases I might even coerce code into something monstrous like
this:

   def test_foo()
     assert_equal(
               ( 'yay!' ),
       ( @o.foo( 'yay' ) ),
     )
   end

The difference to me is that a bunch of programming that initially took
me a very long time has now taken me a very short time to rewrite from
scratch. Think years to weeks. The end result is vastly superior in
every way to me. Faster, clearer, fully tested. Most importantly I'm
enjoying myself!

I know that this means that if I ever manage to function with regular
style conventions I will be forced to re-rewrite everything to follow
them. If it came to that, I would be pleased to do it.. I love that
kind of grunt work. =)

I know I'm learning bad habits, my code will be "unreadable" to others,
I may not be able to read the source of others very well, and there are
probably lots of other issues.. but I needed a new way to approach
programming. It's either that or I just give up.
   

*Hurrrah for you. There is a growing body of people out there who have realized that shorthand is idiosyncratic and often unreadable except to the "literati" in any special group. I've listened to them since the days of COBOL (which is still around and fairly healthy) and before. The problem with COBOL was not it's verbosity, but it's lack of modern structure and object orientation. These deficits have been largely dealt with in recent versions, so COBOL continues to go forward. The generation of programmers who wrote COBOL were in many cases converted accountants and other business types, so they really did not care about constructs like +=, -=, etc., etc., ad infinitum. What they wanted was readable code, and through COBOL, they largely got it. Now do understand that the most horrendous spaghetti code could be written in COBOL, but there were many who understood that and wrote beautifully structured code back before that was even a popular term. Now, all that was not meant to suggest the use of COBOL, but to suggest that maximizing source code rather than minimizing it will pay off in the long run.

In the day, I was as good as any at writing really tricky, fast, and short code until I could not move on to other things because no one could maintain my code but me. Then, I adopted a different idea. Except for extremely time critical code, I put together the "two o'clock rule", which basically said that if this code is not going to look familiar and largely self documenting at 2am, 6 months from now, I should find another way to write it. Outside of those critical pieces of code, which should be documented as heavily as possible, performance should be a product of the compiler, not the programmer, and that is the weakness of almost all of the smaller languages, that their compilers just do not receive the resources necessary to produce really powerful optimization. Variable names should be largely self-documenting, even if that requires more characters than the geeks are willing to type, and the omission or inclusion of some special prefix, post-fix, or infix character should not change the meaning of the code, especially not in subtle ways. Where possible, variables should be static rather than dynamic, even if that means a few extra copies or transforms. At least with static variables, debugging is a whole lot easier, and compiler level optimization is orders of magnitude easier. And, for every byte lost to those static variables, there are a few mega or gigabytes lost to dynamic variables that are not garbage collected correctly or that are just created in error.

For all those verbose code sequences (usually much easier for the compiler to handle) and variables, there are auto-completion editors/IDE's that can save most of the keystrokes. Having worked as a maintenance programmer in my early years and as a diagnostician on just anything that came by when I was a Senior Systems Programmer, I can testify to the beauty of the type of code that you are attempting to apologize for. Keep writing it and try to make it the standard wherever you work. If the compiler you are using cannot sufficiently optimize, get another for that language, or get another language, but don't worry too much about that side of things. Almost any modern, well supported language can be used for almost any project, though there are lots of aspects to such selections. Continue to use as small a subset of the language as is necessary to keep your code clear and understandable, and require massive documentation when trickier facets are used.

There will always be coders who can produce unreadable garbage, but every company who employs such should ride herd on them to do what I have noted above. It is still true that the cost of writing code is only 10-20% of the life-cycle cost of a program. I have gone so far as to mandate the use of code beautifiers, so that all code will look like what you have written. The size of the source code is completely irrelevant, and the size of the object code is increasingly so.

Everett L.(Rett) Williams II

···

On Sun, 27 Mar 2011 05:12:51 +0900 > Ryan Davis<ryand-ruby@zenspider.com> wrote:

*

It's just to split off a reply to Ryan from an earlier thread.

···

On Sun, 27 Mar 2011 10:55:21 +0900 Nick Klauer <klauer@gmail.com> wrote:

> I know I'm learning bad habits, my code will be "unreadable" to
> others, I may not be able to read the source of others very well,
> and there are probably lots of other issues.. but I needed a new
> way to approach programming. It's either that or I just give up.

That's fine, but then what is the point of this post? Are you asking
for help with integrating yourself into more of the semantics of the
Ruby Style way of coding? I guess I'm missing something.