atto 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +50 -0
- data/Rakefile +46 -0
- data/bin/atto +5 -0
- data/lib/atto/ansi.rb +40 -0
- data/lib/atto/run.rb +93 -0
- data/lib/atto/test.rb +80 -0
- data/lib/atto.rb +9 -0
- data/test/atto/test_ansi.rb +27 -0
- data/test/atto/test_test.rb +22 -0
- data/test/test_atto.rb +9 -0
- metadata +73 -0
data/README
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
INTRODUCTION
|
2
|
+
|
3
|
+
Atto is an ultra-tiny self-contained testing framework inspired by
|
4
|
+
and partially based on nanotest. It is self-contained in that it needs no
|
5
|
+
external libraries. Every file in this project is,and will remain under 100
|
6
|
+
lines long, comments included.
|
7
|
+
|
8
|
+
|
9
|
+
USAGE
|
10
|
+
|
11
|
+
To use it in your tests, for every ruby file lib/foo/bar.rb in your project,
|
12
|
+
make a test file lib/foo/test_bar.rb and start it with:
|
13
|
+
|
14
|
+
require 'atto'
|
15
|
+
include Atto::Test
|
16
|
+
|
17
|
+
# Then you can add tests like this:
|
18
|
+
assert "A test that will always suceed" do true end
|
19
|
+
# Or like this :
|
20
|
+
assert { Foo::Bar }
|
21
|
+
|
22
|
+
Then run the command atto from your project directory and it will run the tests
|
23
|
+
automatically, every time you change either the lib file or the test file. It
|
24
|
+
will also detect new files being added.
|
25
|
+
|
26
|
+
LICENSE
|
27
|
+
|
28
|
+
The MIT License
|
29
|
+
|
30
|
+
Copyright (c) 2011 Beoran (beoran@rubyforge.org)
|
31
|
+
|
32
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
33
|
+
of this software and associated documentation files (the "Software"), to deal
|
34
|
+
in the Software without restriction, including without limitation the rights
|
35
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
36
|
+
copies of the Software, and to permit persons to whom the Software is
|
37
|
+
furnished to do so, subject to the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be included in
|
40
|
+
all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
43
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
44
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
45
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
46
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
47
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
48
|
+
THE SOFTWARE.
|
49
|
+
|
50
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Rakefile added by John Mair (banisterfiend)
|
2
|
+
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/clean'
|
5
|
+
CLEAN.include("pkg/*.gem")
|
6
|
+
|
7
|
+
|
8
|
+
ATTO_VERSION = "0.9.0"
|
9
|
+
|
10
|
+
def apply_spec_defaults(s)
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = "atto"
|
15
|
+
s.summary = "An ultra-tiny self-contained testing framework."
|
16
|
+
s.description = s.summary + " "
|
17
|
+
s.version = ATTO_VERSION
|
18
|
+
s.author = "Beoran"
|
19
|
+
s.email = 'beoran@rubyforge.org'
|
20
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
21
|
+
s.require_path = 'lib'
|
22
|
+
s.homepage = "https://github.com/beoran/atto"
|
23
|
+
# s.platform = Gem::Platform::CURRENT
|
24
|
+
s.files = ["Rakefile" , "README" ] +
|
25
|
+
FileList["lib/atto.rb", "lib/atto/*.rb",
|
26
|
+
"test/*.rb" , "test/atto/*.rb" ].to_a
|
27
|
+
s.bindir = "bin"
|
28
|
+
s.executables = "atto"
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
32
|
+
pkg.need_zip = false
|
33
|
+
pkg.need_tar = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task :test do
|
38
|
+
for file in FileList["test/*.rb" , "test/atto/*.rb" ] do
|
39
|
+
puts("Running tests for #{file}:")
|
40
|
+
res = system("ruby -I lib #{file}")
|
41
|
+
puts res ? "OK!" : "Failed!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
data/bin/atto
ADDED
data/lib/atto/ansi.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Atto
|
2
|
+
# ANSI colors
|
3
|
+
module Ansi
|
4
|
+
extend self
|
5
|
+
|
6
|
+
ATTRIBUTES = {
|
7
|
+
:reset => 0 , :bold => 1 , :dark => 2 , :underline => 4 ,
|
8
|
+
:blink => 5 , :negative => 7 , :concealed => 8 , :black => 30,
|
9
|
+
:red => 31, :green => 32, :yellow => 33, :blue => 34,
|
10
|
+
:magenta => 35, :cyan => 36, :white => 37, :on_black => 40,
|
11
|
+
:on_red => 41, :on_green => 42, :on_yellow => 43, :on_blue => 44,
|
12
|
+
:on_magenta=> 45, :on_cyan => 46, :on_white => 47, }
|
13
|
+
|
14
|
+
# Replaces symbols witch refer to ANSI escape codes with those escape codes.
|
15
|
+
def color(*args)
|
16
|
+
out = []
|
17
|
+
for arg in args
|
18
|
+
col = ATTRIBUTES[arg]
|
19
|
+
if col
|
20
|
+
out << "\e[#{col}m"
|
21
|
+
else
|
22
|
+
out << arg
|
23
|
+
end
|
24
|
+
end
|
25
|
+
out << "\e[0m"
|
26
|
+
return out
|
27
|
+
end
|
28
|
+
|
29
|
+
# Replaces ansi codes and returns the joined string
|
30
|
+
def color_string(*args)
|
31
|
+
return color(*args).map { |e| e.to_s }.join
|
32
|
+
end
|
33
|
+
|
34
|
+
# puts output colored with ANSI escape codes
|
35
|
+
def puts(*args)
|
36
|
+
Kernel.puts(*self.color(*args))
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
data/lib/atto/run.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Atto
|
2
|
+
# Test autorunner
|
3
|
+
class Run
|
4
|
+
# Shortcut to run main
|
5
|
+
def self.main
|
6
|
+
return self.new.main
|
7
|
+
end
|
8
|
+
|
9
|
+
# Find all Ruby all files under the named dir
|
10
|
+
def all_files(name)
|
11
|
+
return Dir.new(name).inject([]) do |res, e|
|
12
|
+
full = File.join(name, e)
|
13
|
+
if Dir.exist?(full) && e !='.' && e != '..'
|
14
|
+
res += all_files(full)
|
15
|
+
else
|
16
|
+
res << full if full =~ /\.rb\Z/
|
17
|
+
end
|
18
|
+
res
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# updates the timestamp info for files
|
23
|
+
def update_info(files)
|
24
|
+
return files.inject({}) do |res, name|
|
25
|
+
stat = File.stat(name)
|
26
|
+
res[name] = Struct.new(:mtime).new(stat.mtime)
|
27
|
+
res
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# matches libfiles wih testfiles
|
32
|
+
def match_files(libfiles, testfiles)
|
33
|
+
return libfiles.inject({}) do |res, libname|
|
34
|
+
testname = libname.dup
|
35
|
+
where = libname.rindex(File::Separator)
|
36
|
+
testname[where]= File::Separator + 'test_'
|
37
|
+
testname[File.join('','lib','')] = File.join('','test','')
|
38
|
+
res[libname] = testname if testfiles.member?(testname)
|
39
|
+
res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Runs a list of tests
|
44
|
+
def run_tests(list)
|
45
|
+
return list.inject({}) do |results, file|
|
46
|
+
puts("Running tests for #{file}:")
|
47
|
+
res = system("ruby -I #@libdir -I #@testdir #{file}")
|
48
|
+
puts res ? "OK!" : "Failed!"
|
49
|
+
results[file] = Time.now
|
50
|
+
results
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Checks if a test file must run
|
55
|
+
def must_run(ran_tests, k, v)
|
56
|
+
ran_tests[k] ? ran_tests[k] <= v.mtime : true
|
57
|
+
end
|
58
|
+
|
59
|
+
# updates all state info
|
60
|
+
def update_all
|
61
|
+
@libfiles = all_files(@libdir)
|
62
|
+
@testfiles = all_files(@testdir)
|
63
|
+
@matchfiles= match_files(@libfiles, @testfiles)
|
64
|
+
@libinfo = update_info(@libfiles)
|
65
|
+
@testinfo = update_info(@testfiles)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Main, runs the tests when needed
|
69
|
+
def main
|
70
|
+
@projdir = ARGV[0] || Dir.pwd
|
71
|
+
@libdir = File.join(@projdir, ARGV[1] || 'lib')
|
72
|
+
@testdir = File.join(@projdir, ARGV[2] || 'test')
|
73
|
+
update_all
|
74
|
+
@ran_tests = run_tests(@testfiles)
|
75
|
+
loop do
|
76
|
+
update_all
|
77
|
+
torun = @testinfo.select do |k,v|
|
78
|
+
must_run(@ran_tests, k, v)
|
79
|
+
end
|
80
|
+
extra = @libinfo.select do |k,v|
|
81
|
+
linked = @matchfiles[k]
|
82
|
+
linked ? must_run(@ran_tests, linked, v) : false
|
83
|
+
end.map { |k,v| @matchfiles[k] }
|
84
|
+
run_tests(torun.keys + extra).each { |k,v| @ran_tests[k] = v }
|
85
|
+
sleep(1)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if __FILE__ == $0
|
92
|
+
Atto::Run.main
|
93
|
+
end
|
data/lib/atto/test.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
module Atto
|
4
|
+
# Tiny module for test driven development. Use with include Atto::Test.
|
5
|
+
module Test
|
6
|
+
extend self
|
7
|
+
@@failures, @@dots, @@messages = [], [], []
|
8
|
+
|
9
|
+
# Returns the file and line of the calling context
|
10
|
+
def parse_stack(stack=caller)
|
11
|
+
return *(stack.first.match(/(.*):(\d+)/)[1..2])
|
12
|
+
end
|
13
|
+
|
14
|
+
# Formats a message that reporst on any test failiures
|
15
|
+
def format_failure(message, stack = caller)
|
16
|
+
# file, line =
|
17
|
+
return "(%s:%0.3d) %s" % [*parse_stack(stack), message]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Formats an exception backtrace to a string.
|
21
|
+
def format_exception(raised, msg = "")
|
22
|
+
return msg + raised.to_s + "\n" + raised.backtrace.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a failiure for the given raised and result state
|
26
|
+
# Returns nil if no failure
|
27
|
+
def make_failure(res, raised, msg, stack)
|
28
|
+
return nil if res
|
29
|
+
if raised
|
30
|
+
return format_failure(msg || format_exception(raised, "Exception!\n"), stack)
|
31
|
+
end
|
32
|
+
return format_failure(msg || "Assertion failed!", stack)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Makes a dot for the given raised and result state
|
36
|
+
def make_dot(res, raised)
|
37
|
+
return res ? '.' : ( raised ? 'E' : 'F')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Calls a block safely with a timeout
|
41
|
+
def run_block(delay = 10, &block)
|
42
|
+
res, raised = nil, nil
|
43
|
+
begin
|
44
|
+
Timeout.timeout(delay) do res = block.call ; end
|
45
|
+
rescue
|
46
|
+
raised = $!
|
47
|
+
end
|
48
|
+
return res, raised
|
49
|
+
end
|
50
|
+
|
51
|
+
# Test assertion.
|
52
|
+
def assert(msg=nil, file=nil, line=nil, delay=10, stack=caller, &block)
|
53
|
+
res, raised = run_block(delay, &block)
|
54
|
+
@@dots << make_dot(res, raised)
|
55
|
+
failure = make_failure(res, raised, msg, stack)
|
56
|
+
@@failures << failure if failure
|
57
|
+
if msg
|
58
|
+
@@messages << ( failure ? msg + " (failed) " : msg)
|
59
|
+
end
|
60
|
+
res
|
61
|
+
end
|
62
|
+
|
63
|
+
# Results of the tests
|
64
|
+
def self.results
|
65
|
+
aid = @@dots.join + "\n" + @@failures.join("\n") + "\n"
|
66
|
+
col = @@failures.empty? ? :green : :red
|
67
|
+
aid << Atto::Ansi.color_string(col, "=" * 78)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Describes the tests
|
71
|
+
def self.describe_tests
|
72
|
+
@@messages.join(".\n") + ".\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
at_exit {
|
76
|
+
puts results unless results.strip.empty?;
|
77
|
+
exit @@failures.empty?
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
data/lib/atto.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Atto is a tiny KISS library full of useful functionality for TDD and BDD.
|
2
|
+
module Atto
|
3
|
+
# Ansi colors for red/green display after testing.
|
4
|
+
autoload :Ansi, 'atto/ansi'
|
5
|
+
# Testing
|
6
|
+
autoload :Test, 'atto/test'
|
7
|
+
# Autorunning tests
|
8
|
+
autoload :Run, 'atto/run'
|
9
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'atto'
|
2
|
+
include Atto::Test
|
3
|
+
|
4
|
+
assert("Ansi is defined") { Atto::Ansi }
|
5
|
+
|
6
|
+
assert("Ansi::ATTRIBUTES is defined") { Atto::Ansi::ATTRIBUTES }
|
7
|
+
|
8
|
+
for attr, value in Atto::Ansi::ATTRIBUTES do
|
9
|
+
assert "Attribute #{attr} is colored correctly" do
|
10
|
+
Atto::Ansi.color(attr) == ["\e[#{value}m", "\e[0m"]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
for attr, value in Atto::Ansi::ATTRIBUTES do
|
15
|
+
assert "Attribute with text #{attr} is colored correctly" do
|
16
|
+
Atto::Ansi.color(attr, "hello") == ["\e[#{value}m", "hello", "\e[0m"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
assert "Atto::Ansi#color_string works correctly" do
|
21
|
+
Atto::Ansi.color_string(:green, :on_yellow, "This works!") ==
|
22
|
+
"\e[32m\e[43mThis works!\e[0m"
|
23
|
+
end
|
24
|
+
|
25
|
+
assert "Atto::Ansi#puts works correctly" do
|
26
|
+
(Atto::Ansi.puts :green, :on_yellow, "This works!").nil?
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'atto'
|
2
|
+
include Atto::Test
|
3
|
+
|
4
|
+
assert "Atto is defined" do Atto end
|
5
|
+
assert "Atto::Test is defined" do Atto::Test end
|
6
|
+
assert "Success can be detected" do true end
|
7
|
+
assert "Works with nexted asserts" do
|
8
|
+
assert "This is a nested assert" do true end
|
9
|
+
end
|
10
|
+
|
11
|
+
assert "Works with empty description" do assert { true } end
|
12
|
+
|
13
|
+
assert "Nested asserts keep the return value" do
|
14
|
+
assert { 7 } == 7
|
15
|
+
end
|
16
|
+
|
17
|
+
assert "Atto::Test#describe_tests is defined" do Atto::Test.describe_tests end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
data/test/test_atto.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 0
|
9
|
+
version: 0.9.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Beoran
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-05-07 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: "An ultra-tiny self-contained testing framework. "
|
22
|
+
email: beoran@rubyforge.org
|
23
|
+
executables:
|
24
|
+
- atto
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- Rakefile
|
31
|
+
- README
|
32
|
+
- lib/atto.rb
|
33
|
+
- lib/atto/ansi.rb
|
34
|
+
- lib/atto/run.rb
|
35
|
+
- lib/atto/test.rb
|
36
|
+
- test/test_atto.rb
|
37
|
+
- test/atto/test_ansi.rb
|
38
|
+
- test/atto/test_test.rb
|
39
|
+
- bin/atto
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: https://github.com/beoran/atto
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.7
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: An ultra-tiny self-contained testing framework.
|
72
|
+
test_files: []
|
73
|
+
|