Rob said:
I'm having trouble trying to figure out how to customize an
assertion
message when running unit tests. In particular, I want to check the
permissions on a file, so I have something like:
assert_equal(0755, File.stat(test_file).mode & 0777)
If it fails, I get a message like:
<493> expected but was
<420>.
and of course I would like the expected and actual permissions to be
displayed in octal rather than decimal. How can I do that?
Perhaps something like: ...
1) Failure:
test_bad_file_mode(SomeTest) [-:9]:
Mode of some_file.
<"0755"> expected but was
<"0644">.
2 tests, 2 assertions, 1 failures, 0 errors
This is certainly an improvement on my version, but it is not
completely
satisfying - the reason being that by explicitly converting the
permissions
to a string they get displayed as strings, i.e., I would like to see:
<755> expected
rather than:
Note that I'm doing the conversion to octal myself with the '%#o' and
String#%
It would be better to pull this into a helper method:
$ ruby -r'test/unit'
class SomeTest < Test::Unit::TestCase
def assert_mode(expected_mode, actual_mode, message=nil)
assert_equal '%#o'%expected_mode, '%#o'%actual_mode, message
end
def setup
@test_file = 'some_file'
File.open(@test_file, 'w') {|f| f.write "Hello!"}
end
def test_bad_file_mode
File.chmod(0644, @test_file)
assert_mode 0755, File.stat(@test_file).mode & 0777, "Mode of
#{@test_file}"
end
def test_good_file_mode
File.chmod(0755, @test_file)
assert_mode 0755, File.stat(@test_file).mode & 0777, "Mode of
#{@test_file}"
end
end
__END__
Loaded suite -
Started
F.
Finished in 0.0107 seconds.
1) Failure:
test_bad_file_mode(SomeTest)
[-:3:in `assert_mode'
-:13:in `test_bad_file_mode']:
Mode of some_file.
<"0755"> expected but was
<"0644">.
2 tests, 2 assertions, 1 failures, 0 errors
I'm not sure I understand this - what's the advantage of defining the
assert_mode method over using the already defined methods?
Look at the resulting test and it's failure message:
assert_mode 0755, File.stat(@test_file).mode & 0777
<"0755"> expected but was
<"0644">.
Compared to what you had to start:
assert_equal(0755, File.stat(test_file).mode & 0777)
<493> expected but was
<420>.
Pretty close, no?
Yes, because I want also to check for being read-only in addition to
being
executable in the file permissions.
But you could go all the way with:
$ cat ml_mode_test.rb
require 'test/unit'
module Test
module Unit
module Assertions
##
# Asserts that the octal modes are equal.
# If given a +:mask+ option, will only compare those bits.
#
# Example:
# assert_mode 0444, File.stat(name).mode, "Always
readable", :mask => 0777
#
def assert_mode(expected_mode, actual_mode,
options_or_message=nil, options=nil)
if options.nil? && Hash === options_or_message
message, options = nil, options_or_message
elsif
message = options_or_message
end
full_message = message ? message.chomp+"\n" : ''
full_message << "<%#o> expected but was\n<%#o>"%
[expected_mode, actual_mode]
if Hash === options && options.has_key?
mask)
mask = options[:mask]
expected_mode &= mask
actual_mode &= mask
full_message << " (applying %#o mask)"%mask
end
assert_block(full_message) { expected_mode == actual_mode }
end
end
end
end
class SomeTest < Test::Unit::TestCase
def setup
@test_file = 'some_file'
File.open(@test_file, 'w') {|f| f.write "Hello!"}
File.chmod(0644, @test_file)
end
def test_with_equal
assert_equal 0755, File.stat(@test_file).mode & 0777
end
def test_with_equal_and_message
assert_equal 0755, File.stat(@test_file).mode & 0777, "equal?"
end
def test_with_mode
assert_mode 0755, File.stat(@test_file).mode & 0777
end
def test_with_mode_and_mask
assert_mode 0755, File.stat(@test_file).mode, :mask => 0777
end
def test_with_mode_and_message
assert_mode 0755, File.stat(@test_file).mode & 0777, "executable?"
end
def test_with_mode_big_finish
assert_mode 0755, File.stat(@test_file).mode,
"executable?", :mask => 0777
end
end
__END__
rab:code/ruby $ ruby ml_mode_test.rb
Loaded suite ml_mode_test
Started
FFFFFF
Finished in 0.074508 seconds.
1) Failure:
test_with_equal(SomeTest) [ml_mode_test.rb:42]:
<493> expected but was
<420>.
2) Failure:
test_with_equal_and_message(SomeTest) [ml_mode_test.rb:46]:
equal?.
<493> expected but was
<420>.
3) Failure:
test_with_mode(SomeTest)
[ml_mode_test.rb:27:in `assert_mode'
ml_mode_test.rb:50:in `test_with_mode']:
<0755> expected but was
<0644>
4) Failure:
test_with_mode_and_mask(SomeTest)
[ml_mode_test.rb:27:in `assert_mode'
ml_mode_test.rb:54:in `test_with_mode_and_mask']:
<0755> expected but was
<0100644> (applying 0777 mask)
5) Failure:
test_with_mode_and_message(SomeTest)
[ml_mode_test.rb:27:in `assert_mode'
ml_mode_test.rb:58:in `test_with_mode_and_message']:
executable?
<0755> expected but was
<0644>
6) Failure:
test_with_mode_big_finish(SomeTest)
[ml_mode_test.rb:27:in `assert_mode'
ml_mode_test.rb:62:in `test_with_mode_big_finish']:
executable?
<0755> expected but was
<0100644> (applying 0777 mask)
6 tests, 6 assertions, 6 failures, 0 errors
It just depends on how far you want to take it.
-Rob
Rob Biedenharn
http://agileconsultingllc.com
(e-mail address removed)