Forum: Ruby custom assertion message for unit tests

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4d36f6edbdcdf94ed95d38eb57cac30f?d=identicon&s=25 Will Parsons (Guest)
on 2009-02-05 00:00
(Received via mailing list)
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?
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2009-02-05 01:35
(Received via mailing list)
On Feb 4, 2009, at 5:59 PM, Will Parsons wrote:

>
> and of course I would like the expected and actual permissions to be
> displayed in octal rather than decimal.  How can I do that?
>
> --
> Will


Perhaps something like:

$ ruby -r'test/unit'
class SomeTest < Test::Unit::TestCase
   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_equal '0755', '%#o'%[File.stat(@test_file).mode & 0777],
"Mode of #{@test_file}"
   end

   def test_good_file_mode
     File.chmod(0755, @test_file)

     assert_equal '0755', '%#o'%[File.stat(@test_file).mode & 0777],
"Mode of #{@test_file}"
   end
end
__END__
Loaded suite -
Started
F.
Finished in 0.025823 seconds.

   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


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


Do you really want
   assert File.stat(@test_file).executable?
instead of a specific mode?

-Rob

Rob Biedenharn    http://agileconsultingllc.com
Rob@AgileConsultingLLC.com
4d36f6edbdcdf94ed95d38eb57cac30f?d=identicon&s=25 Will Parsons (Guest)
on 2009-02-05 02:40
(Received via mailing list)
Rob Biedenharn wrote:
>> <493> expected but was
>      @test_file = 'some_file'
>      File.chmod(0755, @test_file)
>
>    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:

  <"0755"> expected

>
>
> F.
> 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?

> Do you really want
>    assert File.stat(@test_file).executable?
> instead of a specific mode?

Yes, because I want also to check for being read-only in addition to
being
executable in the file permissions.
Aafa8848c4b764f080b1b31a51eab73d?d=identicon&s=25 Phlip (Guest)
on 2009-02-05 03:00
(Received via mailing list)
Will Parsons wrote:

>
> and of course I would like the expected and actual permissions to be
> displayed in octal rather than decimal.  How can I do that?

(Unless if you use Ruby 1.8.7), install gem assert2, then write:

   assert{ '755' == (File.stat(test_file).mode & 0777).to_s(8) }

When that fails, it prints out every expression, with its intermediate
value,
including those bitfields' decimal representations, and

   1) Failure:
test_assert_classic_message(Assert21Suite)
     [/cygdrive/c/Users/Phlip/.UNA/2/1/1/assert2/lib/assert2.rb:214:in
`assert_'
      /cygdrive/c/Users/Phlip/.UNA/2/1/1/assert2/lib/assert2.rb:76:in
`assert'
      test/assert2_suite.rb:403:in `test_assert_classic_message']:

assert{ "755" == ( File.stat(test_file).mode() & 511 ).to_s(8) }
   --> false - should pass
                       test_file                   -->
"test/assert2_suite.rb"
                 File.stat(test_file)              --> #<File::Stat***
              File.stat(test_file).mode()          --> 33216
         ( File.stat(test_file).mode() & 511 )     --> 448
     ( File.stat(test_file).mode() & 511 ).to_s(8) --> "700".

29 tests, 115 assertions, 1 failures, 0 errors

All assertions should reflect everything they possibly can at failure
time,
without too much excess verbiage when you write them. They should be
easy to
write and comprehensive when they fail. Assert{ 2.0 } maximizes your
bang-buck
ratio there!
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2009-02-05 04:30
(Received via mailing list)
On Feb 4, 2009, at 8:39 PM, Will Parsons wrote:
>>> 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:
...
> completely
>> Note that I'm doing the conversion to octal myself with the '%#o' and
>>   def setup
>>   def test_good_file_mode
>> Finished in 0.0107 seconds.
>
> 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?

>> Do you really want
>>   assert File.stat(@test_file).executable?
>> instead of a specific mode?
>
> Yes, because I want also to check for being read-only in addition to
> being
> executable in the file permissions.
>
> --
> Will

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
Rob@AgileConsultingLLC.com
Aafa8848c4b764f080b1b31a51eab73d?d=identicon&s=25 Phlip (Guest)
on 2009-02-05 04:55
(Received via mailing list)
Will Parsons wrote:

> Yes, because I want also to check for being read-only in addition to being
> executable in the file permissions.

If I felt the request to take the "" off of "0775" sounded a little
petty, this
would probably be on account of I'm disturbed by so much effort to
achieve 0775
when "File(...).readonly? == true" is a little bit more readable!

How about assert{ `ls -l #{filename.inspect}` =~ /-rwxr-wr-w/ } ?
Cb6bbc826cd7d9238a2fae344958f7ec?d=identicon&s=25 Sandor Szücs (Guest)
on 2009-02-05 12:00
(Received via mailing list)
Maybe it is not necessary to customize the assertion so much.

On 04.02.2009, at 23:59, Will Parsons wrote:

> I would like the expected and actual permissions to be
> displayed in octal rather than decimal.  How can I do that?


irb(main):005:0> "420".to_i
=> 420
irb(main):006:0> "420".to_i.to_s(8)
=> "644"
irb(main):007:0> "420".to_i.to_s(8).to_i
=> 644

regards, Sandor
Szücs
851acbab08553d1f7aa3eecad17f6aa9?d=identicon&s=25 Ken Bloom (Guest)
on 2009-02-05 17:10
(Received via mailing list)
On Wed, 04 Feb 2009 22:55:46 +0000, Will Parsons wrote:

>
> and of course I would like the expected and actual permissions to be
> displayed in octal rather than decimal.  How can I do that?

All of the standard test/unit assertions let you pass a message to be
printed to explain the error, which will print in addition to the
automatic message. So store the mode in a local variable so you can use
it in both places.

acutalmode=File.stat(test_file).mode & 0777
assert_equal 0755, actualmode, "#{test_file} should have mode 755, but
has mode %o instead." % [actualmode]

Or to supress the automatic message altogether and only print your
custom
message:

acutalmode=File.stat(test_file).mode & 0777
assert_block ("#{test_file} should have mode 755,
but has mode %o instead." % [actualmode]) {0755 == actualmode}

--Ken
A056bb40ae992a9b4815847b8fdac298?d=identicon&s=25 Will Parsons (Guest)
on 2009-02-05 18:30
(Received via mailing list)
Sandor Szücs wrote:
>=> "644"
> irb(main):007:0> "420".to_i.to_s(8).to_i
>=> 644

Tricky, but it works!
A056bb40ae992a9b4815847b8fdac298?d=identicon&s=25 Will Parsons (Guest)
on 2009-02-05 18:35
(Received via mailing list)
Ken Bloom wrote:
>> <493> expected but was
> acutalmode=File.stat(test_file).mode & 0777
> assert_equal 0755, actualmode, "#{test_file} should have mode 755, but
> has mode %o instead." % [actualmode]
>
> Or to supress the automatic message altogether and only print your custom
> message:
>
> acutalmode=File.stat(test_file).mode & 0777
> assert_block ("#{test_file} should have mode 755,
> but has mode %o instead." % [actualmode]) {0755 == actualmode}

Thanks!  This is just what I was looking for.
This topic is locked and can not be replied to.