cuporter 0.3.2 → 0.3.3

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.
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