Brian Candler wrote:
Bil Kleb wrote:
Sounds like you're pining for Python's doctest?
doctest — Test interactive Python examples — Python 3.12.1 documentation
Ah, now that's a really interesting way of thinking about
examples/testing: in the form of an irb session. You can write your
tests just by mucking about in irb, and when it makes sense, just paste
the output somewhere.
> foo = generate_foo
=> #<Foo:0xb7cd041c @attr1="hello", @attr2="world">
> foo.attr1
=> "hello"
> foo.attr2
=> "world"
This has been done : I found it quite some time ago on the Web and
polished it a bit :
#!/usr/bin/env ruby
# ---------------------------------------------------
# Copyright 2007 Clinton Forbes
# Modified Michel Demazure 11/07
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/\.
# ---------------------------------------------------
# Put this in the script directory of your Rails app
# this script is inspired by the doctest feature in Python:
# (http://docs.python.org/lib/module-doctest.html\)
# :although I never did get around to reading the original Python code.
···
#
# Feel free to improve upon this script, on the condition that you post
# a comment on
http://clintonforbes.blogspot.com/2007/08/doctest-for-ruby-and-rails.html
# and let me know about it so I can use it as well.
#
# to use, just put some doctests in your code and run this tool using
#
# script/doctest
# doctests look like this
=begin
#doctest Check that 1 + 1 = 2
x = 1
=> 1
x + x
=> 3
2 + 3
=> 6
=end
# or like this
#=begin
##doctest Test creating a Member
#>> m = Member.new()
#=> #nil, "name"=>nil, "hashed_password"=>nil, "admin"=>false,
"reset_key"=>nil, "newsletter_level"=>nil, "created_at"=>nil,
"email"=>nil}>
#>> m.name = "Clinton"
#=> "Clinton"
#>> m.admin = true
#=end
# or like this
=begin
#doctest Check that 1 + 2 = 3
irb(main):001:0> 1 + 2
=> 3
irb(main):002:0> 2 + 3
=> 5
=end
#get all of our Rails stuff
#require File.dirname(__FILE__) + '/../config/boot'
#require File.dirname(__FILE__) + '/../config/environment'
#build array of .rb files
#only looks in ./app directory by default. you can change this if you
keep
#extra code in other places (eg. ./vendor/plugins)
# CODE_REGEX caters for standard IRB prompt and Rails script/console
# prompt.
CODE_REGEX = Regexp.new(/(>>|irb.*?>) (.*)/)
RESULT_REGEX = Regexp.new(/=> (.*)/)
def get_ruby_files(dir_name)
ruby_file_names =
Dir.foreach(dir_name) do |file_name|
unless file_name == '.' || file_name == '..'
full_name = File.join(dir_name, file_name)
if /.*\.rb$/ =~ full_name
ruby_file_names << full_name
elsif File.directory? full_name
sub_files = get_ruby_files(full_name)
ruby_file_names.concat(sub_files) unless sub_files.empty?
end
end
end
ruby_file_names
end
# When running tests, addresses of objects are never likely
# to be the same, so we wipe them out so tests don't fail
#
# for example: #
def normalize_result(input)
input.gsub(/:0x([a-f0-9]){8}/, ':0xXXXXXXXX')
end
def failure_report(statement, expected_result, result)
report = "\n FAILED" #add line number logic here
report << " Code: " << statement << "\n"
report << " Expected: " << expected_result << "\n"
report << " But got: " << result
end
def run_doc_tests(doc_test)
execution_context = binding()
statement, report = '', ''
wrong, passed = 0, 0
doc_test.split("\n").each do |line|
case line
when CODE_REGEX
statement << CODE_REGEX.match(line)[2]
when RESULT_REGEX
expected_result = normalize_result(RESULT_REGEX.match(line)[1])
result = normalize_result(eval(statement,
execution_context).inspect)
unless result == expected_result
report << failure_report(statement, expected_result, result)
wrong += 1
else
passed += 1
end
statement = ''
end
end
return passed, wrong, report
end
def process_ruby_file(file_name)
tests, succeeded, failed = 0, 0, 0
file_report = ''
code = File.read(file_name)
code.scan(/=begin\s#doctest ([^\n]*)\n(.*?)=end/m) do |doc_test|
file_report << "\n Testing '#{doc_test[0]}'..."
passed, wrong, report = run_doc_tests(doc_test[1])
file_report += (wrong == 0 ? "OK" : report)
tests += 1
succeeded += passed
failed += wrong
end
file_report = "Processing '#{file_name}'" + file_report unless
file_report.empty?
return tests, succeeded, failed, file_report
end
ruby_file_names = get_ruby_files(File.dirname(__FILE__))
total_report = "Looking for doctests in #{ruby_file_names.length}
files\n"
total_files, total_tests, total_succeeded, total_failed = 0, 0, 0, 0
ruby_file_names.each do |ruby_file_name|
tests, succeeded, failed, report = process_ruby_file(ruby_file_name)
total_files += 1 if tests > 0
total_tests += tests
total_succeeded += succeeded
total_failed += failed
total_report << report << "\n" unless report.empty?
end
total_report << "Total files: #{total_files}, total tests:
#{total_tests}, assertions succeeded: #{total_succeeded}, assertions
failed: #{total_failed}"
puts total_report
--
Posted via http://www.ruby-forum.com/\.