The unit test that won't.

P

Phillip Gawlowski

Aspiring to be a good programmer, I'm using Test::Unit for ClothRed,
writing the test before I write the code, even.

Which is all well and good, but I have a test, that produces an error
*while it is executed* and *not* in the error report:

test_textformatting(TestClothRedFormatting):
TypeError: can't convert nil into String
../test/../lib/clothred.rb:22:in `gsub!'
../test/../lib/clothred.rb:22:in `to_textile'
../test/../lib/clothred.rb:21:in `collect!'
../test/../lib/clothred.rb:21:in `to_textile'
../test/test_formatting.rb:43:in `test_textformatting'
../test/test_formatting.rb:41:in `each'
../test/test_formatting.rb:41:in `test_textformatting'

2 tests, 1 assertions, 0 failures, 1 errors

My tests look like this:

#Works:
def test_tags
assert_equal("**bold**", ClothRed.new("<b>bold</b>").to_textile)
end

#Doesn't work:
def test_textformatting
FORMATTING_STRINGS.each do |html, textile|
test_html = ClothRed.new(html)
test_html.to_textile
assert_equal(textile,test_html)
end
end

The Array is as follows:

FORMATTING_STRINGS = [
["<b>bold</b>","**bold**"], ["<strong>strong</strong>", "*strong*"],
["<em>emphasized</em>", "_emphasized_"],
["<i>italics</i>", "__italics__"],
["<cite>citation</cite>", "??citation??"],
["<code>ClothRed#to_textile</code>", "@ClothRed#to_textile@"],
["<del>delete</del>", "-delete-"],
["<ins>underline</ins>", "+underline+"],
["<sup>superscript</sup>","^superscript^"],
["<sub>subscript</sub>","~subscript~"]
]


An improvised test run produces this:

c:\test.rb
**bold**
_emphasized_
__italics__

c:\cat test.rb
# test.rb
# 11. April 2007
#

require 'clothred'



TEST = '<b>bold</b>
<em>emphasized</em>
<i>italics</i>'

test = ClothRed.new(TEST)

puts test.to_textile


My Ruby version:
c:\ruby -v
ruby 1.8.5 (2006-12-25 patchlevel 12) [i386-mswin32]

The output of the test suggests, that I'm doing something wrong in my
test, that my test is buggy, and not my code.

Can somebody enlighten me?

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan.110mb.com/

Rule of Open-Source Programming #6:

The user is always right unless proven otherwise by the developer.
 
B

Brian Candler

def test_textformatting
FORMATTING_STRINGS.each do |html, textile|
test_html = ClothRed.new(html)
test_html.to_textile
assert_equal(textile,test_html)

Hmm, it looks like test_html is not a string here, but some other sort of
object, so did you mean

assert_equal(textfile, test_html.to_s) ?

or else

result = test_html.to_textile
assert_equal(textile, result) ?

It depends whether your 'to_textile' method really changes the internal
state of your ClothRed object, or whether its return value is the thing
you're interested in checking.

B.
 
P

Phillip Gawlowski

Daniel said:
As Brian says, I'm not really sure what test_html.to_textile leaves
test_html as but why not go back to what works for you. It seems
simpler to
me also.

def test_textformatting
FORMATTING_STRINGS.each do |html, textile|
assert_equal(textile, ClothRed.new(html).to_textile )
end
end

also a failing message wouldn't go astray. Something like

def test_textformatting
FORMATTING_STRINGS.each do |html, textile|
transformed = ClothRed.new(html).to_textile
assert_equal(textile, transformed ), "\"#{html}\" should have
transformed to \"#{textile}\¨ but was \"#{transformed}\""
end
end

just my 0.02

Thanks for the input guys, looks like the error *was* in my code after all.
Here's the why:

ClothRed#to_textile used Array#collect! to iterate over the string that
was to be transformed, which let the first test complete successfully as
it was only testing for *one* condition. As soon as I change #collect!
to #each, the code behaved as the test expected. Although why this
happens, I'm not sure (I guess the receiver of the block is the "count"
for the block, and not the elements in the Array).

Which leads to the discovery of another bug now, which is in my regex.

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan.110mb.com/

Eek! That was supposed to be My Special Law, _MY_ special law, I tell
you!

T/
 
B

Brian Candler

ClothRed#to_textile used Array#collect! to iterate over the string that
was to be transformed, which let the first test complete successfully as
it was only testing for *one* condition. As soon as I change #collect!
to #each, the code behaved as the test expected. Although why this
happens, I'm not sure (I guess the receiver of the block is the "count"
for the block, and not the elements in the Array).

I don't understand what you've written above - you might want to paste an
example. For both Array#each and Array#collect!, the values passed to the
block are the elements of the array. The difference is in what happens to
the value returned by the block; #each ignores it, #collect! replaces the
original array element with it.

As a separate point though: if to_textile changes the state of your ClothRed
object, you might want to consider calling it something else.

Normally, a to_foo method returns an object of type foo, and does not change
the state of the receiver. Compare Object#to_yaml, Method#to_proc,
Object#to_enum and so on.

Personally I would be surprised to find a Ruby library with a "to_textile"
method, where the main purpose of the function was to change the state of
the receiver, and _not_ to return a textile object.

Regards,

Brian.
 
P

Phillip Gawlowski

Brian said:
I don't understand what you've written above - you might want to paste an
example. For both Array#each and Array#collect!, the values passed to the
block are the elements of the array. The difference is in what happens to
the value returned by the block; #each ignores it, #collect! replaces the
original array element with it.

Ah, that cleared up *my* confusion. I wanted #each in the first place,
but made mistakes in writing my code.

Well, the learning never stops.
As a separate point though: if to_textile changes the state of your ClothRed
object, you might want to consider calling it something else.

I have changed that behavior. #to_textile is non-destructive (at least
it should be, I have to add a test for that).
Personally I would be surprised to find a Ruby library with a "to_textile"
method, where the main purpose of the function was to change the state of
the receiver, and _not_ to return a textile object.

Yes, I'd expect that from #to-textile!, too, which was my intention in
the first place.

--
Phillip "CynicalRyan" Gawlowski
http://cynicalryan.110mb.com/

Rule of Open-Source Programming #48:

The number of items on a project's to-do list always grows or remains
constant.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top