testdoc 0.0.2
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/History.txt +4 -0
- data/Manifest.txt +19 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +72 -0
- data/Rakefile +28 -0
- data/bin/testdoc +16 -0
- data/lib/testdoc/footer.html.erb +5 -0
- data/lib/testdoc/header.html.erb +13 -0
- data/lib/testdoc/template.debug.erb +21 -0
- data/lib/testdoc/template.html.erb +61 -0
- data/lib/testdoc/testdocoptions.rb +607 -0
- data/lib/testdoc/testdocparser.rb +178 -0
- data/lib/testdoc.rb +10 -0
- data/lib/testdoc_module.rb +182 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +3 -0
- data/test/test_testdoc.rb +11 -0
- metadata +96 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
# TestDocParser
|
2
|
+
|
3
|
+
class TestPlan
|
4
|
+
attr_accessor :tests, :title, :comments
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
class TestItem
|
9
|
+
attr_accessor :tasks, :title, :id, :number_of_checks, :checks_tasks_count
|
10
|
+
end
|
11
|
+
|
12
|
+
class Task
|
13
|
+
attr_accessor :checks, :title, :id
|
14
|
+
end
|
15
|
+
|
16
|
+
class Check
|
17
|
+
attr_accessor :title, :id
|
18
|
+
end
|
19
|
+
|
20
|
+
class TestDocParser
|
21
|
+
|
22
|
+
attr_accessor :options
|
23
|
+
|
24
|
+
def initialize(lines,filename)
|
25
|
+
@lines = lines
|
26
|
+
@filename = filename
|
27
|
+
@line_counter = 0
|
28
|
+
read_line()
|
29
|
+
@progress = $stderr
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(msg)
|
33
|
+
puts @filename + ":" + @src_line_number.to_s + " Error: " + msg
|
34
|
+
puts " # " + @tag.to_s + ":" + @param
|
35
|
+
exit(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_line
|
39
|
+
src_line = @lines[@line_counter]
|
40
|
+
if src_line == nil then
|
41
|
+
@tag = ""
|
42
|
+
@param = ""
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
@tag = src_line[0]
|
46
|
+
@param = src_line[1]
|
47
|
+
@src_line_number = src_line[2]
|
48
|
+
@line_counter = @line_counter + 1
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
|
52
|
+
def progress(char)
|
53
|
+
unless @options.quiet
|
54
|
+
@progress.print(char)
|
55
|
+
@progress.flush
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Directive 'testplan:' is optional, but is expected to be first.
|
61
|
+
def process_testplan
|
62
|
+
testplans = []
|
63
|
+
@testplans_counter = 0
|
64
|
+
|
65
|
+
if(@tag == :testplan) then
|
66
|
+
testplan = TestPlan.new
|
67
|
+
testplan.title = @param.split("#")[0]
|
68
|
+
testplan.comments = @param.split("#")[1]
|
69
|
+
read_line()
|
70
|
+
else
|
71
|
+
testplan = TestPlan.new
|
72
|
+
end
|
73
|
+
testplan.tests = process_tests()
|
74
|
+
testplans[@testplans_counter] = testplan
|
75
|
+
@testplans_counter += 1
|
76
|
+
|
77
|
+
# count number of tasks and checks for each test
|
78
|
+
# for setting correct rowspan in html
|
79
|
+
if (testplans == nil)
|
80
|
+
return nil
|
81
|
+
end
|
82
|
+
testplans.each do |testplan|
|
83
|
+
if (testplan.tests == nil)
|
84
|
+
return nil
|
85
|
+
end
|
86
|
+
testplan.tests.each do |test|
|
87
|
+
checks_tasks_count = 0
|
88
|
+
|
89
|
+
test.tasks.each do |task|
|
90
|
+
if(task.checks.size == 0)
|
91
|
+
checks_tasks_count += 1
|
92
|
+
end
|
93
|
+
task.checks.each do |check|
|
94
|
+
checks_tasks_count += 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
# number_of_checks is an alias for checks_tasks_count
|
98
|
+
test.number_of_checks = checks_tasks_count.to_s
|
99
|
+
test.checks_tasks_count = checks_tasks_count.to_s
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# return parsed testplan
|
104
|
+
return testplans
|
105
|
+
end
|
106
|
+
|
107
|
+
def process_tests
|
108
|
+
tests = []
|
109
|
+
@tests_counter = 0
|
110
|
+
if (@tag == :test)
|
111
|
+
while(@tag == :test ) do
|
112
|
+
progress("t")
|
113
|
+
test = TestItem.new()
|
114
|
+
test.title = @param
|
115
|
+
test.id = (@tests_counter + 1).to_s
|
116
|
+
read_line()
|
117
|
+
|
118
|
+
test.tasks = process_tasks
|
119
|
+
tests[@tests_counter] = test
|
120
|
+
@tests_counter += 1
|
121
|
+
end
|
122
|
+
return tests
|
123
|
+
else
|
124
|
+
progress("-")
|
125
|
+
# progress("Warning: no directives found")
|
126
|
+
## error("Could not find any 'test:' directives.")
|
127
|
+
return nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def process_tasks
|
132
|
+
tasks = []
|
133
|
+
@tasks_counter = 0
|
134
|
+
if(@tag == :check) then
|
135
|
+
error("Excepted 'task:' directive before 'check:' directive.")
|
136
|
+
end
|
137
|
+
while(@tag == :task) do
|
138
|
+
progress(".")
|
139
|
+
task = Task.new
|
140
|
+
task.title = @param
|
141
|
+
task.id = (@tests_counter + 1).to_s + "." + (@tasks_counter + 1).to_s
|
142
|
+
read_line()
|
143
|
+
|
144
|
+
task.checks = process_checks
|
145
|
+
# # pad tree with 'empty' checks
|
146
|
+
# if(task.checks.size == 0)then
|
147
|
+
# checks = []
|
148
|
+
# check = Check.new
|
149
|
+
# check.title = "- Empty -"
|
150
|
+
# check.id = "0"
|
151
|
+
# checks[0] = check
|
152
|
+
# task.checks = checks
|
153
|
+
# end
|
154
|
+
tasks[@tasks_counter] = task
|
155
|
+
@tasks_counter += 1
|
156
|
+
end
|
157
|
+
return tasks
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def process_checks
|
162
|
+
checks = []
|
163
|
+
@checks_counter = 0
|
164
|
+
while(@tag == :check) do
|
165
|
+
progress("c")
|
166
|
+
check = Check.new
|
167
|
+
check.title = @param
|
168
|
+
check.id = (@tests_counter + 1).to_s
|
169
|
+
check.id = check.id + "." + (@tasks_counter + 1).to_s
|
170
|
+
check.id = check.id + "." + (@checks_counter + 1).to_s
|
171
|
+
checks[@checks_counter] = check
|
172
|
+
@checks_counter += 1
|
173
|
+
read_line()
|
174
|
+
end
|
175
|
+
return checks
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
data/lib/testdoc.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
|
2
|
+
module TestDoc
|
3
|
+
|
4
|
+
require 'erb'
|
5
|
+
require File.dirname(__FILE__) + '/testdoc/testdocoptions'
|
6
|
+
require File.dirname(__FILE__) + '/testdoc/testdocparser'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
# module TestDoc
|
11
|
+
|
12
|
+
|
13
|
+
class TestDoc
|
14
|
+
|
15
|
+
GENERATORS = {} # Not in use
|
16
|
+
|
17
|
+
# Name of the dotfile that contains the description of files to be
|
18
|
+
# processed in the current directory
|
19
|
+
DOT_DOC_FILENAME = ".document"
|
20
|
+
|
21
|
+
# Main method
|
22
|
+
def document(argv)
|
23
|
+
|
24
|
+
options = Options.instance
|
25
|
+
options.parse(argv, GENERATORS)
|
26
|
+
@generated_content = ""
|
27
|
+
|
28
|
+
puts "Title:" + options.title
|
29
|
+
@title = options.title
|
30
|
+
header = File.dirname(__FILE__) + "/testdoc/header.html.erb"
|
31
|
+
@generated_content = process_template(header, nil) unless options.text
|
32
|
+
@progress = $stderr unless options.quiet
|
33
|
+
@num_files = 0
|
34
|
+
@options = options
|
35
|
+
files = options.files
|
36
|
+
files = ["."] if files.empty?
|
37
|
+
|
38
|
+
file_list = normalized_file_list(options, files, true)
|
39
|
+
|
40
|
+
template_file = File.dirname(__FILE__) + "/testdoc/template.html.erb"
|
41
|
+
if(options.text) then
|
42
|
+
template_file = File.dirname(__FILE__) + "/testdoc/template.debug.erb"
|
43
|
+
end
|
44
|
+
|
45
|
+
file_list.each do |fn|
|
46
|
+
$stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet
|
47
|
+
content = File.open(fn, "r") {|f| f.read}
|
48
|
+
testdoc_directives = []
|
49
|
+
testdoc_directives = parse_file(content)
|
50
|
+
parser = TestDocParser.new(testdoc_directives,File.basename(fn))
|
51
|
+
parser.options = options
|
52
|
+
testplans = []
|
53
|
+
testplans = parser.process_testplan
|
54
|
+
if(testplans) then
|
55
|
+
@generated_content += process_template(template_file,testplans)
|
56
|
+
@num_files += 1
|
57
|
+
end
|
58
|
+
|
59
|
+
# basename = File.basename(fn).split("\.")[0]
|
60
|
+
# puts "DEBUG" + basename + ".html"
|
61
|
+
end
|
62
|
+
|
63
|
+
if(not options.quiet) then
|
64
|
+
puts ''
|
65
|
+
puts ''
|
66
|
+
puts 'Generating TestDoc HTML: testplan.html...'
|
67
|
+
# puts "Files: #@num_files"
|
68
|
+
puts "Parsed files: #@num_files"
|
69
|
+
end
|
70
|
+
|
71
|
+
if( not options.text) then
|
72
|
+
footer = File.dirname(__FILE__) + "/testdoc/footer.html.erb"
|
73
|
+
@generated_content += process_template(footer, nil)
|
74
|
+
output_file = File.new("testplan.html", "w")
|
75
|
+
output_file.puts @generated_content
|
76
|
+
else
|
77
|
+
puts @generated_content
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def process_template(template_file,testplans)
|
83
|
+
template = File.open(template_file, "r") {|f| f.read}
|
84
|
+
rhtml = ERB.new(template, safe_level = 0, trim_mode = 1 )
|
85
|
+
generated_html = rhtml.result(b=binding() ).gsub(/\n\n/,"\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
# Exctract comments from file and return it in an array
|
89
|
+
def parse_file(content)
|
90
|
+
|
91
|
+
if /\t/ =~ content
|
92
|
+
tab_width = Options.instance.tab_width
|
93
|
+
content = content.split(/\n/).map do |line|
|
94
|
+
1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
|
95
|
+
line
|
96
|
+
end .join("\n")
|
97
|
+
end
|
98
|
+
@content = content
|
99
|
+
@content << "\n" unless @content[-1,1] == "\n"
|
100
|
+
|
101
|
+
testdoc_array = []
|
102
|
+
counter = 0
|
103
|
+
|
104
|
+
symbol = nil
|
105
|
+
line_number = 0
|
106
|
+
content.split(/\n/).map do |line|
|
107
|
+
line_number = line_number + 1
|
108
|
+
|
109
|
+
if line =~ /.*#.*test:(.*)/i then
|
110
|
+
symbol = :test
|
111
|
+
testdoc_array[counter] = [:test,$1.gsub(/^\s+/, ""),line_number]
|
112
|
+
counter = counter + 1
|
113
|
+
elsif line =~ /.*#.*task:(.*)/i then
|
114
|
+
testdoc_array[counter] = [:task,$1.gsub(/^\s+/, ""),line_number]
|
115
|
+
counter = counter + 1
|
116
|
+
symbol = :task
|
117
|
+
elsif line =~ /.*#.*check:(.*)/i then
|
118
|
+
testdoc_array[counter] = [:check,$1.gsub(/^\s+/, ""),line_number]
|
119
|
+
counter = counter + 1
|
120
|
+
symbol = :check
|
121
|
+
elsif line =~ /.*#.*testplan:(.*)/i then
|
122
|
+
testdoc_array[counter] = [:testplan,$1.gsub(/^\s+/, "") + "#",line_number]
|
123
|
+
counter = counter + 1
|
124
|
+
symbol = :testplan
|
125
|
+
elsif line =~ /.*#(.*)/ && symbol != nil then
|
126
|
+
testdoc_array[counter - 1][1] = testdoc_array[counter - 1][1] + " " + $1.gsub(/^ */, ' ')
|
127
|
+
|
128
|
+
else
|
129
|
+
symbol = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
return testdoc_array
|
135
|
+
end
|
136
|
+
|
137
|
+
# Given a list of files and directories, create a list
|
138
|
+
# of all the Ruby files they contain.
|
139
|
+
|
140
|
+
def normalized_file_list(options, relative_files, force_doc = false, exclude_pattern=nil)
|
141
|
+
file_list = []
|
142
|
+
|
143
|
+
relative_files.each do |rel_file_name|
|
144
|
+
next if exclude_pattern && exclude_pattern =~ rel_file_name
|
145
|
+
stat = File.stat(rel_file_name)
|
146
|
+
case type = stat.ftype
|
147
|
+
when "file"
|
148
|
+
next if @last_created and stat.mtime < @last_created
|
149
|
+
file_list << rel_file_name.sub(/^\.\//, '') ## if force_doc || ParserFactory.can_parse(rel_file_name)
|
150
|
+
when "directory"
|
151
|
+
next if rel_file_name == "CVS" || rel_file_name == ".svn"
|
152
|
+
# puts "DEBUG: rel_file_name: " + rel_file_name
|
153
|
+
dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
|
154
|
+
if File.file?(dot_doc)
|
155
|
+
file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
|
156
|
+
else
|
157
|
+
file_list.concat(list_files_in_directory(rel_file_name, options))
|
158
|
+
end
|
159
|
+
else
|
160
|
+
raise TestDocError.new("I can't deal with a #{type} #{rel_file_name}")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
file_list
|
164
|
+
end
|
165
|
+
|
166
|
+
# Return a list of the files to be processed in
|
167
|
+
# a directory. We know that this directory doesn't have
|
168
|
+
# a .document file, so we're looking for real files. However
|
169
|
+
# we may well contain subdirectories which must
|
170
|
+
# be tested for .document files
|
171
|
+
def list_files_in_directory(dir, options)
|
172
|
+
normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
class TestDocError < Exception
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/testdoc.rb'}"
|
9
|
+
puts "Loading testdoc gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: testdoc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- FIXME full name
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-09 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: "Generate testplans from annotated sourcecode. Author: Thomas Flemming, thomasfl(snabela)usit.uio.no"
|
36
|
+
email:
|
37
|
+
- FIXME email
|
38
|
+
executables:
|
39
|
+
- testdoc
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- PostInstall.txt
|
46
|
+
- README.rdoc
|
47
|
+
files:
|
48
|
+
- History.txt
|
49
|
+
- Manifest.txt
|
50
|
+
- PostInstall.txt
|
51
|
+
- README.rdoc
|
52
|
+
- Rakefile
|
53
|
+
- lib/testdoc.rb
|
54
|
+
- lib/testdoc_module.rb
|
55
|
+
- lib/testdoc/testdocoptions.rb
|
56
|
+
- lib/testdoc/testdocparser.rb
|
57
|
+
- lib/testdoc/footer.html.erb
|
58
|
+
- lib/testdoc/header.html.erb
|
59
|
+
- lib/testdoc/template.html.erb
|
60
|
+
- lib/testdoc/template.debug.erb
|
61
|
+
- script/console
|
62
|
+
- script/destroy
|
63
|
+
- script/generate
|
64
|
+
- test/test_helper.rb
|
65
|
+
- test/test_testdoc.rb
|
66
|
+
- bin/testdoc
|
67
|
+
has_rdoc: true
|
68
|
+
homepage: FIX (url)
|
69
|
+
post_install_message: PostInstall.txt
|
70
|
+
rdoc_options:
|
71
|
+
- --main
|
72
|
+
- README.rdoc
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
version:
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project: testdoc
|
90
|
+
rubygems_version: 1.3.1
|
91
|
+
signing_key:
|
92
|
+
specification_version: 2
|
93
|
+
summary: Generate testplans from annotated sourcecode
|
94
|
+
test_files:
|
95
|
+
- test/test_helper.rb
|
96
|
+
- test/test_testdoc.rb
|