testml-lite 0.0.1
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/.gemspec +19 -0
- data/CHANGELOG.yaml +3 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.rdoc +12 -0
- data/Rakefile +64 -0
- data/lib/testml/lite.rb +218 -0
- data/test/lib/test_testml_lite.rb +15 -0
- data/test/test1.rb +17 -0
- metadata +58 -0
data/.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
GemSpec = Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'testml-lite'
|
5
|
+
gem.version = '0.0.1'
|
6
|
+
gem.license = 'MIT'
|
7
|
+
gem.required_ruby_version = '>= 1.9.1'
|
8
|
+
|
9
|
+
gem.authors << 'Ingy döt Net'
|
10
|
+
gem.email = 'ingy@ingy.net'
|
11
|
+
gem.summary = 'Acmeist Unit Test Framework'
|
12
|
+
gem.description = <<-'.'
|
13
|
+
TestML is an Acmeist testing framework. TestML::Lite is smaller bootstrap
|
14
|
+
version of TestML.
|
15
|
+
.
|
16
|
+
gem.homepage = 'http://testml.org'
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.lines.map{|l|l.chomp}
|
19
|
+
end
|
data/CHANGELOG.yaml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright © 2012 Ingy döt Net
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the ‘Software’), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= testml-lite - Lite Version of TestML for Ruby
|
2
|
+
|
3
|
+
TestML is an Acmeist Unit Test language/framework. TestML::Lite is a lighter,
|
4
|
+
bootstrapping implementation of that.
|
5
|
+
|
6
|
+
= Synopsis
|
7
|
+
|
8
|
+
require 'testml/lite'
|
9
|
+
|
10
|
+
= Copyright
|
11
|
+
|
12
|
+
Copyright (c) 2012 Ingy döt Net. See LICENSE for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Load Gem constants from the gemspec
|
2
|
+
GemSpecFile = '.gemspec'
|
3
|
+
load GemSpecFile
|
4
|
+
GemName = GemSpec.name
|
5
|
+
GemVersion = GemSpec.version
|
6
|
+
GemDir = "#{GemName}-#{GemVersion}"
|
7
|
+
GemFile = "#{GemDir}.gem"
|
8
|
+
DevNull = '2>/dev/null'
|
9
|
+
|
10
|
+
# Require the Rake libraries
|
11
|
+
require 'rake'
|
12
|
+
require 'rake/testtask'
|
13
|
+
require 'rake/clean'
|
14
|
+
|
15
|
+
task :default => 'help'
|
16
|
+
|
17
|
+
CLEAN.include GemDir, GemFile, 'data.tar.gz', 'metadata.gz'
|
18
|
+
|
19
|
+
desc 'Run the tests'
|
20
|
+
task :test do
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.verbose = true
|
23
|
+
t.test_files = FileList['test/*.rb']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Build the gem'
|
28
|
+
task :build => [:clean, :test] do
|
29
|
+
sh "gem build #{GemSpecFile}"
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Install the gem'
|
33
|
+
task :install => [:build] do
|
34
|
+
sh "gem install #{GemFile}"
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Build, unpack and inspect the gem'
|
38
|
+
task :distdir => [:build] do
|
39
|
+
sh "tar xf #{GemFile} #{DevNull}"
|
40
|
+
Dir.mkdir GemDir
|
41
|
+
Dir.chdir GemDir
|
42
|
+
sh "tar xzf ../data.tar.gz #{DevNull}"
|
43
|
+
puts "\n>>> Entering sub-shell for #{GemDir}..."
|
44
|
+
system ENV['SHELL']
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'Build and push the gem'
|
48
|
+
task :release => [:build] do
|
49
|
+
sh "gem push #{GemFile}"
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Print a description of the gem'
|
53
|
+
task :desc do
|
54
|
+
puts "Gem: '#{GemName}' (version #{GemVersion})"
|
55
|
+
puts
|
56
|
+
puts GemSpec.description.gsub /^/, ' '
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'List the Rakefile tasks'
|
60
|
+
task :help do
|
61
|
+
puts 'The following rake tasks are available:'
|
62
|
+
puts
|
63
|
+
puts `rake -T`.gsub /^/, ' '
|
64
|
+
end
|
data/lib/testml/lite.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
# Make sure tests have access to the application libs and the testing libs.
|
2
|
+
$:.unshift Dir.getwd + '/lib'
|
3
|
+
$:.unshift Dir.getwd + '/test/lib'
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
module TestML
|
8
|
+
def self.run &runner
|
9
|
+
name = _get_test_name
|
10
|
+
$testml_runners[name] = runner
|
11
|
+
TestML::Lite::TestCases.send(:define_method, name) do
|
12
|
+
_run_runner name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.data data
|
17
|
+
$testml_data[_get_test_name] = data
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.require_or_skip module_
|
21
|
+
require module_
|
22
|
+
rescue exit
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
$testml_runners ||= {}
|
27
|
+
$testml_data ||= {}
|
28
|
+
|
29
|
+
class TestML::Lite < Test::Unit::TestCase
|
30
|
+
def data input
|
31
|
+
unless input.match /\n/
|
32
|
+
File.open(input, 'r') {|f| input = f.read}
|
33
|
+
end
|
34
|
+
@testml = _parse_tml input
|
35
|
+
end
|
36
|
+
|
37
|
+
def label text
|
38
|
+
@label = text
|
39
|
+
end
|
40
|
+
|
41
|
+
def eval expr, callback=nil
|
42
|
+
_assert_testml
|
43
|
+
expr = _parse_expr expr if expr.kind_of? String
|
44
|
+
callback ||= method 'run_test'
|
45
|
+
_get_blocks(expr).each do |block|
|
46
|
+
$error = nil
|
47
|
+
callback.call(block, expr)
|
48
|
+
raise $error if $error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_test block, expr
|
53
|
+
expr = _parse_expr expr if expr.kind_of? String
|
54
|
+
block = _get_blocks(expr, [block]).first or return
|
55
|
+
_evaluate expr, block
|
56
|
+
end
|
57
|
+
|
58
|
+
def assert_equal got, want, block
|
59
|
+
label = block.kind_of?(String) ? block : block[:title]
|
60
|
+
if got != want
|
61
|
+
on_fail if respond_to? 'on_fail'
|
62
|
+
File.open('/tmp/got', 'w') {|f| f.write got}
|
63
|
+
File.open('/tmp/want', 'w') {|f| f.write want}
|
64
|
+
puts `diff -u /tmp/want /tmp/got`
|
65
|
+
end
|
66
|
+
super want, got, label
|
67
|
+
end
|
68
|
+
|
69
|
+
def assert_match got, want, block
|
70
|
+
label = block.kind_of?(String) ? block : block[:title]
|
71
|
+
super want, got, label
|
72
|
+
end
|
73
|
+
|
74
|
+
def Catch any=nil
|
75
|
+
fail "Catch called, but no error occurred" unless $error
|
76
|
+
error = $error
|
77
|
+
$error = nil
|
78
|
+
return error.message
|
79
|
+
end
|
80
|
+
|
81
|
+
def _run_runner name
|
82
|
+
@test_name = name
|
83
|
+
$testml_runners[name].call(self)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _assert_testml
|
87
|
+
return if defined? @testml
|
88
|
+
raise "No testml data provided" unless $testml_data[@test_name]
|
89
|
+
data $testml_data[@test_name]
|
90
|
+
end
|
91
|
+
|
92
|
+
def _evaluate expr, block
|
93
|
+
expr = ['', expr] if expr.kind_of? String
|
94
|
+
func = expr.first
|
95
|
+
args = expr[1..expr.length-1].collect do |ex|
|
96
|
+
if ex.kind_of? Array
|
97
|
+
_evaluate ex, block
|
98
|
+
elsif ex =~ /\A\*(\w+)\z/
|
99
|
+
block[:points][$1]
|
100
|
+
else
|
101
|
+
ex
|
102
|
+
end
|
103
|
+
end
|
104
|
+
# TODO @error
|
105
|
+
return if $error and func != 'Catch'
|
106
|
+
return args.first if func.empty?
|
107
|
+
args << block if func =~ /^assert_/
|
108
|
+
begin
|
109
|
+
return method(func).call(*args)
|
110
|
+
rescue => e
|
111
|
+
$error = e
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def _get_blocks expr, blocks=@testml
|
116
|
+
want = expr.flatten.grep(/^\*/).collect{|ex| ex.gsub /^\*/, ''}
|
117
|
+
only = blocks.select{|block| block['ONLY']}
|
118
|
+
blocks = only unless only.empty?
|
119
|
+
final = []
|
120
|
+
blocks.each do |block|
|
121
|
+
next if block['SKIP']
|
122
|
+
ok = true
|
123
|
+
want.each do |w|
|
124
|
+
unless block[:points][w]
|
125
|
+
ok = false
|
126
|
+
break
|
127
|
+
end
|
128
|
+
end
|
129
|
+
if ok
|
130
|
+
final << block
|
131
|
+
break if block['LAST']
|
132
|
+
end
|
133
|
+
end
|
134
|
+
return final
|
135
|
+
end
|
136
|
+
|
137
|
+
def _parse_expr expr
|
138
|
+
left, op, right = [], nil, nil
|
139
|
+
side = left
|
140
|
+
while expr.length != 0
|
141
|
+
t = _get_token expr
|
142
|
+
if t =~ /^(==|~~)$/
|
143
|
+
op = t == '==' ? 'assert_equal' : 'assert_match'
|
144
|
+
left = side
|
145
|
+
side = right = []
|
146
|
+
else
|
147
|
+
side = [side] if side.size >= 2
|
148
|
+
side.unshift t
|
149
|
+
end
|
150
|
+
end
|
151
|
+
right = side if right
|
152
|
+
return left unless right
|
153
|
+
left = left.first if left.size == 1
|
154
|
+
right = right.first if right.size == 1
|
155
|
+
return [op, left, right]
|
156
|
+
end
|
157
|
+
|
158
|
+
def _get_token expr
|
159
|
+
if expr.sub! /^(\w+)\(([^\)]+)\)\.?/, ''
|
160
|
+
token, args = [$1], $2
|
161
|
+
token.concat(
|
162
|
+
args.split(/,\s*/).map {|t| t.sub /^(['"])(.*)\1$/, '\2'}
|
163
|
+
)
|
164
|
+
elsif expr.sub! /^\s*(==|~~)\s*/, ''
|
165
|
+
token = $1
|
166
|
+
elsif expr.sub! /^([\*\w]+)\.?/, ''
|
167
|
+
token = $1
|
168
|
+
end
|
169
|
+
return token
|
170
|
+
end
|
171
|
+
|
172
|
+
def _parse_tml string
|
173
|
+
string.gsub! /^#.*\n/, ''
|
174
|
+
string.gsub! /^\\/, ''
|
175
|
+
string.gsub! /^\s*\n/, ''
|
176
|
+
blocks = string.split /(^===.*?(?=^===|\z))/m
|
177
|
+
blocks.reject!{|b| b.empty?}
|
178
|
+
blocks.each do |block|
|
179
|
+
block.gsub! /\n+\z/, "\n"
|
180
|
+
end
|
181
|
+
|
182
|
+
array = []
|
183
|
+
blocks.each do |string_block|
|
184
|
+
block = {}
|
185
|
+
string_block.gsub! /^===\ +(.*?)\ *\n/, '' \
|
186
|
+
or fail "No block title! #{string_block}"
|
187
|
+
block[:title] = $1
|
188
|
+
while !string_block.empty? do
|
189
|
+
if string_block.gsub! /\A---\ +(\w+):\ +(.*)\n/, '' or
|
190
|
+
string_block.gsub! /\A---\ +(\w+)\n(.*?)(?=^---|\z)/m, ''
|
191
|
+
key, value = $1, $2
|
192
|
+
else
|
193
|
+
raise "Failed to parse TestML string:\n#{string_block}"
|
194
|
+
end
|
195
|
+
block[:points] ||= {}
|
196
|
+
block[:points][key] = value
|
197
|
+
|
198
|
+
if key =~ /^(ONLY|SKIP|LAST)$/
|
199
|
+
block[key] = true
|
200
|
+
end
|
201
|
+
end
|
202
|
+
array << block
|
203
|
+
end
|
204
|
+
return array
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Find the first call stack entry that looks like: .../test/xxx-yyy.rb
|
209
|
+
# and return 'test_xxx_yyy' as the test name.
|
210
|
+
def _get_test_name
|
211
|
+
name = caller.map { |s|
|
212
|
+
s.split(':').first
|
213
|
+
}.grep(/(^|\/)test\/[-\w]+\.rb$/).first or fail
|
214
|
+
name.gsub!(/^(?:.*\/)?test\/([-\w+]+)\.rb$/, '\1').gsub(/[^\w]+/, '_')
|
215
|
+
return "test_#{name}"
|
216
|
+
end
|
217
|
+
|
218
|
+
module TestML::Lite::TestCases;end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require './lib/testml/lite'
|
2
|
+
|
3
|
+
class TestTestMLLite < TestML::Lite
|
4
|
+
include TestML::Lite::TestCases
|
5
|
+
|
6
|
+
def json_load json
|
7
|
+
require 'json'
|
8
|
+
JSON.load json
|
9
|
+
end
|
10
|
+
|
11
|
+
def yaml_dump object
|
12
|
+
require 'yaml'
|
13
|
+
YAML.dump(object).sub(/\A---\n/, '')
|
14
|
+
end
|
15
|
+
end
|
data/test/test1.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require './test/lib/test_testml_lite'
|
2
|
+
|
3
|
+
TestML.require_or_skip 'json'
|
4
|
+
TestML.require_or_skip 'yaml'
|
5
|
+
|
6
|
+
TestML.run do |t|
|
7
|
+
t.eval '*json.json_load.yaml_dump == *yaml'
|
8
|
+
end
|
9
|
+
|
10
|
+
TestML.data <<'...'
|
11
|
+
=== Array
|
12
|
+
--- json: [1,2,3]
|
13
|
+
--- yaml
|
14
|
+
- 1
|
15
|
+
- 2
|
16
|
+
- 3
|
17
|
+
...
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: testml-lite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ingy döt Net
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-20 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'TestML is an Acmeist testing framework. TestML::Lite is smaller bootstrap
|
15
|
+
|
16
|
+
version of TestML.
|
17
|
+
|
18
|
+
'
|
19
|
+
email: ingy@ingy.net
|
20
|
+
executables: []
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- .gemspec
|
25
|
+
- CHANGELOG.yaml
|
26
|
+
- Gemfile
|
27
|
+
- LICENSE
|
28
|
+
- README.rdoc
|
29
|
+
- Rakefile
|
30
|
+
- lib/testml/lite.rb
|
31
|
+
- test/lib/test_testml_lite.rb
|
32
|
+
- test/test1.rb
|
33
|
+
homepage: http://testml.org
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.9.1
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.23
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Acmeist Unit Test Framework
|
58
|
+
test_files: []
|