cuporter 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/README.textile +123 -44
  2. data/Rakefile +5 -5
  3. data/bin/cuporter +19 -11
  4. data/lib/cuporter.rb +15 -26
  5. data/lib/cuporter/cli/options.rb +95 -22
  6. data/lib/cuporter/document.rb +23 -0
  7. data/lib/cuporter/document/html_document.rb +82 -0
  8. data/lib/cuporter/extensions/nokogiri.rb +46 -0
  9. data/lib/cuporter/feature_parser.rb +38 -19
  10. data/lib/cuporter/filter.rb +1 -0
  11. data/lib/cuporter/formatters/csv.rb +69 -0
  12. data/lib/cuporter/formatters/text.rb +166 -0
  13. data/lib/cuporter/formatters/xml_to_html.xslt +315 -0
  14. data/lib/cuporter/node.rb +7 -83
  15. data/lib/cuporter/node/node_base.rb +114 -0
  16. data/lib/cuporter/node/numbering.rb +32 -0
  17. data/lib/cuporter/node/sorting.rb +27 -0
  18. data/lib/cuporter/node/tagged_node.rb +22 -0
  19. data/lib/cuporter/node/totalling.rb +19 -0
  20. data/lib/cuporter/node/types.rb +158 -0
  21. data/lib/cuporter/node_parser.rb +62 -0
  22. data/lib/cuporter/report/feature_report.rb +23 -0
  23. data/lib/cuporter/report/report_base.rb +69 -0
  24. data/lib/cuporter/report/tag_report.rb +27 -7
  25. data/lib/cuporter/report/tree_report.rb +24 -0
  26. data/lib/cuporter/tag_nodes_parser.rb +94 -0
  27. data/public/images/ajax-loader.gif +0 -0
  28. data/public/images/file.gif +0 -0
  29. data/public/images/folder-closed.gif +0 -0
  30. data/public/images/folder.gif +0 -0
  31. data/public/images/minus.gif +0 -0
  32. data/public/images/plus.gif +0 -0
  33. data/public/images/treeview-black-line.gif +0 -0
  34. data/public/images/treeview-black.gif +0 -0
  35. data/public/images/treeview-default-line.gif +0 -0
  36. data/public/images/treeview-default.gif +0 -0
  37. data/public/images/treeview-famfamfam-line.gif +0 -0
  38. data/public/images/treeview-famfamfam.gif +0 -0
  39. data/public/images/treeview-gray-line.gif +0 -0
  40. data/public/images/treeview-gray.gif +0 -0
  41. data/public/images/treeview-red-line.gif +0 -0
  42. data/public/images/treeview-red.gif +0 -0
  43. data/public/javascripts/expand-collapse.js +47 -0
  44. data/public/javascripts/jquery-min.js +167 -0
  45. data/public/javascripts/jquery.treeview.js +267 -0
  46. data/public/javascripts/treeview-loader.js +11 -0
  47. data/public/stylesheets/cuporter.css +101 -0
  48. data/{lib/cuporter/formatter/name_report/style.css → public/stylesheets/feature_style.css} +17 -18
  49. data/public/stylesheets/jquery.treeview.css +75 -0
  50. data/{lib/cuporter/formatter/tag_report/style.css → public/stylesheets/tag_style.css} +17 -22
  51. data/public/stylesheets/tree_style.css +104 -0
  52. metadata +52 -37
  53. data/lib/cuporter/example_set_node.rb +0 -15
  54. data/lib/cuporter/formatter/csv_text_methods.rb +0 -20
  55. data/lib/cuporter/formatter/cuporter.css +0 -64
  56. data/lib/cuporter/formatter/html_methods.rb +0 -122
  57. data/lib/cuporter/formatter/html_node_writer.rb +0 -104
  58. data/lib/cuporter/formatter/jquery-min.js +0 -154
  59. data/lib/cuporter/formatter/name_report/csv.rb +0 -12
  60. data/lib/cuporter/formatter/name_report/html.rb +0 -48
  61. data/lib/cuporter/formatter/name_report/html_node_writer.rb +0 -18
  62. data/lib/cuporter/formatter/name_report/text.rb +0 -16
  63. data/lib/cuporter/formatter/name_report/text_node_writer.rb +0 -16
  64. data/lib/cuporter/formatter/pretty_text_methods.rb +0 -22
  65. data/lib/cuporter/formatter/tag_report/csv.rb +0 -12
  66. data/lib/cuporter/formatter/tag_report/html.rb +0 -35
  67. data/lib/cuporter/formatter/tag_report/html_node_writer.rb +0 -19
  68. data/lib/cuporter/formatter/tag_report/text.rb +0 -14
  69. data/lib/cuporter/formatter/tag_report/text_node_writer.rb +0 -17
  70. data/lib/cuporter/formatter/text_methods.rb +0 -19
  71. data/lib/cuporter/formatter/writer.rb +0 -33
  72. data/lib/cuporter/name_list_parser.rb +0 -44
  73. data/lib/cuporter/node_numberer.rb +0 -18
  74. data/lib/cuporter/report/name_report.rb +0 -19
  75. data/lib/cuporter/report/report.rb +0 -22
  76. data/lib/cuporter/tag_list_node.rb +0 -54
  77. data/lib/cuporter/tag_list_parser.rb +0 -39
@@ -0,0 +1,32 @@
1
+ # Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ module Node
4
+ module Numbering
5
+ class Numberer
6
+
7
+ attr_reader :total
8
+
9
+ def initialize
10
+ @total = 0
11
+ end
12
+
13
+ def number(node)
14
+ node.children.each do |child|
15
+ case child.node_name
16
+ when 'scenario', 'example'
17
+ child["number"] = (@total += 1).to_s
18
+ end
19
+ number(child)
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ def number_all_descendants
26
+ @numberer = Numberer.new
27
+ @numberer.number(self)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ module Node
4
+
5
+ module Sorting
6
+ include Comparable
7
+
8
+ def sort_all_descendants!
9
+ sort!
10
+ children.each {|child| child.sort_all_descendants! }
11
+ end
12
+
13
+ # see #NodeSetExtensions in extensions/nokogiri.rb
14
+ def sort!
15
+ return unless has_children?
16
+ sorted_children = children.sort
17
+ self.children = sorted_children
18
+ end
19
+
20
+ def <=>(other)
21
+ (short_cuke_name || name) <=> (other.short_cuke_name || other.name)
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ module Node
4
+ # a node with a list of tags that can be applied to all children
5
+ module Tagged
6
+
7
+ attr_accessor :filter
8
+
9
+ def has_tags?
10
+ tags.size > 0
11
+ end
12
+ def tags
13
+ @tags ||= attributes["tags"].to_s.split(/,\s*/) || []
14
+ end
15
+ def filter_child(node, context_tags = [])
16
+ add_child(node) if @filter.pass?(context_tags | tags | node.tags)
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ module Node
4
+
5
+ module Totalling
6
+ def total
7
+ total!
8
+ children.each {|child| child.total }
9
+ end
10
+
11
+ def total!
12
+ t = search("scenario,example").size
13
+ self["total"] = t.to_s if t > 0
14
+ nil
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,158 @@
1
+ # Copyright 2011 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ module Node
4
+ module Types
5
+ class Report < NodeBase
6
+ def tag_node(tag)
7
+ at("tag[cuke_name='#{tag}']")
8
+ end
9
+
10
+ # remove leaf nodes, i.e., the scenario and scenario outline children
11
+ def defoliate!
12
+ leaves = search("feature > scenario, feature > scenario_outline")
13
+ leaves.remove
14
+ end
15
+
16
+ def remove_files!
17
+ search(:feature).each {|f| f.delete('file_path') }
18
+ end
19
+
20
+ def remove_tags!
21
+ search("*[@tags]").each {|e| e.delete('tags') }
22
+ end
23
+ end
24
+
25
+ class FilterSummary < NodeBase
26
+ def add(filter)
27
+ self << filter_node(:all, filter.all.join(' AND ')) unless filter.all.empty?
28
+ self << filter_node(:any, filter.any.join(' OR ')) unless filter.any.empty?
29
+ self << filter_node(:none, filter.none.join(', ')) unless filter.none.empty?
30
+ end
31
+
32
+ def filter_node(name, text)
33
+ fn = NodeBase.new(name.to_s, document)
34
+ fn['tags'] = text
35
+ fn
36
+ end
37
+
38
+ end
39
+
40
+ module FileSystemNode
41
+ def fs_name
42
+ @fs_name ||= self['fs_name']
43
+ end
44
+ end
45
+
46
+ class Dir < NodeBase
47
+ include FileSystemNode
48
+
49
+ def <=>(other)
50
+ return -1 if other.is_a? File # ensure folders sort higher
51
+ fs_name <=> (other['fs_name'] || other['cuke_name'])
52
+ end
53
+
54
+ end
55
+
56
+ class File < NodeBase
57
+ include FileSystemNode
58
+
59
+ # just total self, don't let any children total themselves. This is so
60
+ # the feature won't re-total itself when its containing file already has.
61
+ def total
62
+ total!
63
+ end
64
+
65
+ def <=>(other)
66
+ return 1 if other.is_a? Dir # ensure folders sort higher
67
+ fs_name <=> (other['fs_name'] || other['cuke_name'])
68
+ end
69
+ end
70
+
71
+ class Tag < NodeBase
72
+ def feature_node(feature)
73
+ at("feature[cuke_name='#{feature[:cuke_name]}'][file_path='#{feature[:file_path]}']")
74
+ end
75
+ end
76
+
77
+ class ScenarioOutline < NodeBase
78
+ include Tagged
79
+
80
+ def example_set_node(es)
81
+ at("examples[cuke_name='#{es[:cuke_name]}']")
82
+ end
83
+
84
+ end
85
+
86
+ class Feature < NodeBase
87
+ include Tagged
88
+
89
+ def scenario_outline_node(scenario_outline)
90
+ at("scenario_outline[cuke_name='#{scenario_outline[:cuke_name]}']")
91
+ end
92
+
93
+ def file_path
94
+ self["file_path"]
95
+ end
96
+
97
+ def file_name
98
+ file_path.split(/\//).last
99
+ end
100
+
101
+ # sort on: file path, name, substring of name after any ':'
102
+ def <=>(other)
103
+ if other.respond_to?(:file_path)
104
+ file_path <=> other.file_path
105
+ else
106
+ super(other)
107
+ end
108
+ end
109
+
110
+ def eql?(other)
111
+ if other.respond_to? :file_path
112
+ return false if file_path != other.file_path
113
+ end
114
+ super(other)
115
+ end
116
+ end
117
+
118
+ # The set of examples in a scenario outline
119
+ class Examples < NodeBase
120
+ include Tagged
121
+
122
+ # don't sort scenario outline examples
123
+ def sort!
124
+ # no op
125
+ end
126
+
127
+ # don't total at the example set level
128
+ def total
129
+ # no op
130
+ end
131
+
132
+ def add_child(other)
133
+ cn = other['cuke_name'].dup
134
+ cn.sub!(/^\|/, '')
135
+ cn.split('|').each do |cell_text|
136
+ cell = Nokogiri::XML::Node.new("span", document)
137
+ cell.content = cell_text.strip
138
+ other << cell
139
+ end
140
+ super(other)
141
+ end
142
+ end
143
+ Scenarios = Examples
144
+
145
+ # Leaf Nodes: won't have children
146
+ class Scenario < NodeBase
147
+ include Tagged
148
+ end
149
+
150
+ class Example < NodeBase
151
+ end
152
+
153
+ class ExampleHeader < NodeBase
154
+ end
155
+ end
156
+ end
157
+ end
158
+
@@ -0,0 +1,62 @@
1
+ # Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
2
+
3
+ module Cuporter
4
+ class NodeParser < FeatureParser
5
+
6
+ # ++sub_expression++ is the paren group in the regex, dereferenced with $1 in the caller
7
+ def new_feature_node(sub_expression, file)
8
+ f = Node.new_node(:Feature, @doc, :cuke_name => sub_expression, :tags => @current_tags, :file_path => file)
9
+ f.filter = @filter
10
+ f
11
+ end
12
+
13
+ def handle_scenario_line(sub_expression)
14
+ if @filter.pass?(@current_tags | @feature.tags)
15
+ @feature.add_child(Node.new_node(:Scenario, @doc, :cuke_name => sub_expression, :tags => @current_tags))
16
+ end
17
+ end
18
+
19
+ def new_scenario_outline_node(sub_expression)
20
+ so = Node.new_node(:ScenarioOutline, @doc, :cuke_name => sub_expression, :tags => @current_tags)
21
+ so.filter = @filter
22
+ so
23
+ end
24
+
25
+ def handle_example_set_line
26
+ if @filter.pass?(@feature.tags | @scenario_outline.tags | @example_set.tags)
27
+ @scenario_outline.add_child @example_set
28
+ end
29
+ end
30
+
31
+ def new_example_set_node(sub_expression)
32
+ es = Node.new_node(:Examples, @doc, :cuke_name => sub_expression, :tags => @current_tags)
33
+ es.filter = @filter
34
+ es
35
+ end
36
+
37
+ def new_example_line(sub_expression)
38
+ example_type = :ExampleHeader
39
+ # if the example set has a child already, then it must be the header
40
+ example_type = :Example if @example_set.has_children?
41
+ @example_set.add_child(Node.new_node(example_type, @doc, :cuke_name => sub_expression))
42
+ end
43
+
44
+ def close_scenario_outline
45
+ if @scenario_outline
46
+ if @example_set
47
+ handle_example_set_line
48
+ @example_set = nil
49
+ end
50
+ @feature.add_child(@scenario_outline) if @scenario_outline.has_children?
51
+ @scenario_outline = nil
52
+ end
53
+ end
54
+
55
+ def initialize(file, doc, filter)
56
+ super(file)
57
+ @filter = filter
58
+ @doc = doc
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ class FeatureReport < ReportBase
4
+
5
+ def report_node
6
+ unless @report
7
+ @report = Cuporter::Node.new_node(:Report, @doc, :title => title, :view => view)
8
+ files.each do |file|
9
+ feature = FeatureParser.node(file, @doc, @filter, root_dir)
10
+ if feature && feature.has_children?
11
+ @report.add_child feature
12
+ end
13
+ end
14
+ end
15
+ @report
16
+ end
17
+
18
+ def title
19
+ @title || "Cucumber Features, List View"
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
2
+ module Cuporter
3
+ class ReportBase
4
+
5
+ attr_reader :filter, :doc, :root_dir, :view
6
+
7
+ def initialize(options)
8
+ @input_file_pattern = options[:input_file_pattern]
9
+ @doc = Cuporter::Document.new_xml
10
+ @view = options[:report]
11
+ @root_dir = options[:root_dir]
12
+ @filter = Filter.new(options[:filter_args])
13
+ @title = options[:title]
14
+ @sort = options[:sort]
15
+ @total = options[:total]
16
+ @number = options[:number]
17
+ @leaves = options[:leaves]
18
+ @show_files = options[:show_files]
19
+ @show_tags = options[:show_tags]
20
+ end
21
+
22
+ def no_leaves?
23
+ !@leaves
24
+ end
25
+
26
+ def sort?
27
+ @sort
28
+ end
29
+
30
+ def total?
31
+ @total
32
+ end
33
+
34
+ def number?
35
+ @number
36
+ end
37
+
38
+ def show_files?
39
+ @show_files
40
+ end
41
+
42
+ def show_tags?
43
+ @show_tags
44
+ end
45
+
46
+ def files
47
+ Dir[@input_file_pattern].collect {|f| File.expand_path f}
48
+ end
49
+
50
+ def self.create(options)
51
+ klass = Cuporter.const_get("#{options[:report].downcase}Report".to_class_name)
52
+ klass.new(options)
53
+ end
54
+
55
+ def build
56
+ report_node.sort_all_descendants! if sort?
57
+ report_node.number_all_descendants if number?
58
+ report_node.total if total?
59
+ report_node.defoliate! if no_leaves?
60
+ report_node.remove_files! unless show_files?
61
+ report_node.remove_tags! unless show_tags?
62
+
63
+ doc.add_filter_summary(@filter)
64
+ doc.add_report report_node
65
+ self
66
+ end
67
+
68
+ end
69
+ end
@@ -1,15 +1,35 @@
1
1
  # Copyright 2010 ThoughtWorks, Inc. Licensed under the MIT License
2
2
  module Cuporter
3
- class TagReport < Report
3
+ class TagReport < ReportBase
4
4
 
5
- def report_node
6
- tags = TagListNode.new("report",[])
5
+ def build_report_node
7
6
  files.each do |file|
8
- feature = FeatureParser.tag_list(file)
9
- tags.merge_tag_nodes(feature) if feature
7
+ FeatureParser.tag_nodes(file, report, @filter, root_dir)
10
8
  end
11
- tags.sort_all_descendants!
12
- tags
9
+ end
10
+
11
+ def report
12
+ @report ||= begin
13
+ r = Cuporter::Node.new_node(:Report, doc, :title => title, :view => view)
14
+ doc.add_filter_summary(@filter)
15
+ doc.add_report r
16
+ r
17
+ end
18
+ end
19
+
20
+ def title
21
+ @title || "Cucumber Tags"
22
+ end
23
+
24
+ def build
25
+ build_report_node
26
+ report.sort_all_descendants! if sort?
27
+ report.search(:tag).each {|f| f.number_all_descendants } if number?
28
+ report.total if total?
29
+ report.defoliate! if no_leaves?
30
+ report.remove_files! unless show_files?
31
+ report.remove_tags! unless show_tags?
32
+ self
13
33
  end
14
34
 
15
35
  end