cuke_modeler 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.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.simplecov +8 -0
  4. data/Gemfile +4 -0
  5. data/History.rdoc +3 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +73 -0
  8. data/Rakefile +38 -0
  9. data/cuke_modeler.gemspec +29 -0
  10. data/features/analysis/test_comparison.feature +123 -0
  11. data/features/analysis/test_manipulation.feature +37 -0
  12. data/features/modeling/background_modeling.feature +75 -0
  13. data/features/modeling/background_output.feature +130 -0
  14. data/features/modeling/directory_modeling.feature +120 -0
  15. data/features/modeling/directory_output.feature +13 -0
  16. data/features/modeling/doc_string_modeling.feature +63 -0
  17. data/features/modeling/doc_string_output.feature +71 -0
  18. data/features/modeling/example_modeling.feature +111 -0
  19. data/features/modeling/example_output.feature +192 -0
  20. data/features/modeling/feature_file_modeling.feature +64 -0
  21. data/features/modeling/feature_file_output.feature +13 -0
  22. data/features/modeling/feature_modeling.feature +164 -0
  23. data/features/modeling/feature_output.feature +244 -0
  24. data/features/modeling/outline_modeling.feature +100 -0
  25. data/features/modeling/outline_output.feature +197 -0
  26. data/features/modeling/row_modeling.feature +77 -0
  27. data/features/modeling/row_output.feature +27 -0
  28. data/features/modeling/scenario_modeling.feature +89 -0
  29. data/features/modeling/scenario_output.feature +147 -0
  30. data/features/modeling/step_modeling.feature +85 -0
  31. data/features/modeling/step_output.feature +52 -0
  32. data/features/modeling/table_modeling.feature +52 -0
  33. data/features/modeling/table_output.feature +42 -0
  34. data/features/modeling/table_row_modeling.feature +67 -0
  35. data/features/modeling/table_row_output.feature +27 -0
  36. data/features/modeling/tag_modeling.feature +58 -0
  37. data/features/modeling/tag_output.feature +16 -0
  38. data/features/step_definitions/action_steps.rb +3 -0
  39. data/features/step_definitions/background_steps.rb +81 -0
  40. data/features/step_definitions/directory_steps.rb +52 -0
  41. data/features/step_definitions/doc_string_steps.rb +63 -0
  42. data/features/step_definitions/feature_file_steps.rb +41 -0
  43. data/features/step_definitions/feature_steps.rb +96 -0
  44. data/features/step_definitions/outline_steps.rb +252 -0
  45. data/features/step_definitions/setup_steps.rb +50 -0
  46. data/features/step_definitions/spec_steps.rb +18 -0
  47. data/features/step_definitions/step_steps.rb +159 -0
  48. data/features/step_definitions/table_steps.rb +54 -0
  49. data/features/step_definitions/tag_steps.rb +61 -0
  50. data/features/step_definitions/test_steps.rb +114 -0
  51. data/features/step_definitions/verification_steps.rb +9 -0
  52. data/features/support/env.rb +27 -0
  53. data/features/support/transforms.rb +3 -0
  54. data/lib/cuke_modeler.rb +29 -0
  55. data/lib/cuke_modeler/background.rb +38 -0
  56. data/lib/cuke_modeler/containing.rb +18 -0
  57. data/lib/cuke_modeler/directory.rb +86 -0
  58. data/lib/cuke_modeler/doc_string.rb +87 -0
  59. data/lib/cuke_modeler/example.rb +184 -0
  60. data/lib/cuke_modeler/feature.rb +147 -0
  61. data/lib/cuke_modeler/feature_element.rb +73 -0
  62. data/lib/cuke_modeler/feature_file.rb +77 -0
  63. data/lib/cuke_modeler/nested.rb +34 -0
  64. data/lib/cuke_modeler/outline.rb +68 -0
  65. data/lib/cuke_modeler/parsing.rb +32 -0
  66. data/lib/cuke_modeler/raw.rb +20 -0
  67. data/lib/cuke_modeler/row.rb +64 -0
  68. data/lib/cuke_modeler/scenario.rb +45 -0
  69. data/lib/cuke_modeler/sourceable.rb +20 -0
  70. data/lib/cuke_modeler/step.rb +214 -0
  71. data/lib/cuke_modeler/table.rb +90 -0
  72. data/lib/cuke_modeler/table_row.rb +64 -0
  73. data/lib/cuke_modeler/tag.rb +62 -0
  74. data/lib/cuke_modeler/taggable.rb +54 -0
  75. data/lib/cuke_modeler/test_element.rb +77 -0
  76. data/lib/cuke_modeler/version.rb +3 -0
  77. data/lib/cuke_modeler/world.rb +113 -0
  78. data/spec/integration/background_integration_spec.rb +72 -0
  79. data/spec/integration/directory_integration_spec.rb +48 -0
  80. data/spec/integration/doc_string_integration_spec.rb +66 -0
  81. data/spec/integration/example_integration_spec.rb +94 -0
  82. data/spec/integration/feature_file_integration_spec.rb +44 -0
  83. data/spec/integration/feature_integration_spec.rb +152 -0
  84. data/spec/integration/outline_integration_spec.rb +92 -0
  85. data/spec/integration/scenario_integration_spec.rb +80 -0
  86. data/spec/integration/step_integration_spec.rb +184 -0
  87. data/spec/integration/table_integration_spec.rb +86 -0
  88. data/spec/integration/table_row_integration_spec.rb +68 -0
  89. data/spec/integration/tag_integration_spec.rb +67 -0
  90. data/spec/integration/world_integration_spec.rb +13 -0
  91. data/spec/spec_helper.rb +30 -0
  92. data/spec/unit/background_unit_spec.rb +55 -0
  93. data/spec/unit/bare_bones_unit_specs.rb +13 -0
  94. data/spec/unit/containing_element_unit_specs.rb +17 -0
  95. data/spec/unit/directory_unit_spec.rb +103 -0
  96. data/spec/unit/doc_string_unit_spec.rb +109 -0
  97. data/spec/unit/example_unit_spec.rb +251 -0
  98. data/spec/unit/feature_element_unit_spec.rb +19 -0
  99. data/spec/unit/feature_element_unit_specs.rb +46 -0
  100. data/spec/unit/feature_file_unit_spec.rb +94 -0
  101. data/spec/unit/feature_unit_spec.rb +135 -0
  102. data/spec/unit/nested_element_unit_specs.rb +36 -0
  103. data/spec/unit/nested_unit_spec.rb +37 -0
  104. data/spec/unit/outline_unit_spec.rb +91 -0
  105. data/spec/unit/parsing_unit_spec.rb +21 -0
  106. data/spec/unit/prepopulated_unit_specs.rb +13 -0
  107. data/spec/unit/raw_element_unit_specs.rb +24 -0
  108. data/spec/unit/raw_unit_spec.rb +25 -0
  109. data/spec/unit/row_unit_spec.rb +55 -0
  110. data/spec/unit/scenario_unit_spec.rb +71 -0
  111. data/spec/unit/sourceable_unit_spec.rb +17 -0
  112. data/spec/unit/sourced_element_unit_specs.rb +18 -0
  113. data/spec/unit/step_unit_spec.rb +259 -0
  114. data/spec/unit/table_row_unit_spec.rb +55 -0
  115. data/spec/unit/table_unit_spec.rb +96 -0
  116. data/spec/unit/tag_unit_spec.rb +51 -0
  117. data/spec/unit/taggable_unit_spec.rb +78 -0
  118. data/spec/unit/tagged_element_unit_specs.rb +63 -0
  119. data/spec/unit/test_element_unit_spec.rb +40 -0
  120. data/spec/unit/test_element_unit_specs.rb +31 -0
  121. data/spec/unit/world_unit_spec.rb +130 -0
  122. metadata +364 -0
@@ -0,0 +1,87 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling the Doc String of a Step.
4
+
5
+ class DocString
6
+
7
+ include Raw
8
+ include Nested
9
+
10
+
11
+ # The content type associated with the doc string
12
+ attr_accessor :content_type
13
+
14
+ # Deprecated
15
+ #
16
+ # The contents of the doc string
17
+ attr_accessor :contents
18
+
19
+ # The contents of the doc string
20
+ attr_accessor :contents_text
21
+
22
+
23
+ # Creates a new DocString object and, if *source* is provided, populates
24
+ # the object.
25
+ def initialize(source = nil)
26
+ @contents = []
27
+ @contents_text = ''
28
+
29
+ parsed_doc_string = process_source(source)
30
+
31
+ build_doc_string(parsed_doc_string) if parsed_doc_string
32
+ end
33
+
34
+ # Returns a gherkin representation of the doc string.
35
+ def to_s
36
+ text = "\"\"\"#{content_type_output_string}\n"
37
+ text << contents_output_string
38
+ text << '"""'
39
+ end
40
+
41
+
42
+ private
43
+
44
+
45
+ def process_source(source)
46
+ case
47
+ when source.is_a?(String)
48
+ parse_doc_string(source)
49
+ else
50
+ source
51
+ end
52
+ end
53
+
54
+ def parse_doc_string(source_text)
55
+ base_file_string = "Feature:\nScenario:\n* step\n"
56
+ source_text = base_file_string + source_text
57
+
58
+ parsed_file = Parsing::parse_text(source_text)
59
+
60
+ parsed_file.first['elements'].first['steps'].first['doc_string']
61
+ end
62
+
63
+ def build_doc_string(doc_string)
64
+ populate_content_type(doc_string)
65
+ populate_contents(doc_string)
66
+ populate_raw_element(doc_string)
67
+ end
68
+
69
+ def populate_content_type(doc_string)
70
+ @content_type = doc_string['content_type'] == "" ? nil : doc_string['content_type']
71
+ end
72
+
73
+ def populate_contents(doc_string)
74
+ @contents = doc_string['value'].split($/, -1)
75
+ @contents_text = doc_string['value']
76
+ end
77
+
78
+ def content_type_output_string
79
+ content_type ? " #{content_type}" : ''
80
+ end
81
+
82
+ def contents_output_string
83
+ contents_text.empty? ? '' : contents_text.gsub('"""', '\"\"\"') + "\n"
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,184 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a Cucumber Examples table.
4
+
5
+ class Example < FeatureElement
6
+
7
+ include Taggable
8
+ include Containing
9
+
10
+
11
+ # The argument rows in the example table
12
+ #
13
+ # todo - Make this a read only method that derives the rows from
14
+ # the row elements
15
+ attr_accessor :rows
16
+
17
+ # The parameters for the example table
18
+ #
19
+ # todo - Make this a read only method that derives the parameters from
20
+ # the row elements
21
+ attr_accessor :parameters
22
+
23
+ # The row elements in the example table
24
+ attr_accessor :row_elements
25
+
26
+
27
+ # Creates a new Example object and, if *source* is provided,
28
+ # populates the object.
29
+ def initialize(source = nil)
30
+ parsed_example = process_source(source)
31
+
32
+ super(parsed_example)
33
+
34
+ @tags = []
35
+ @tag_elements = []
36
+ @rows = []
37
+ @parameters = []
38
+ @row_elements = []
39
+
40
+ build_example(parsed_example) if parsed_example
41
+ end
42
+
43
+ # Adds a row to the example table. The row can be given as a Hash of
44
+ # parameters and their corresponding values or as an Array of values which
45
+ # will be assigned in order.
46
+ def add_row(row)
47
+ case
48
+ when row.is_a?(Array)
49
+ @rows << Hash[@parameters.zip(row.collect { |value| value.strip })]
50
+ @row_elements << Row.new("|#{row.join('|')}|")
51
+ when row.is_a?(Hash)
52
+ @rows << row.each_value { |value| value.strip! }
53
+ @row_elements << Row.new("|#{ordered_row_values(row).join('|')}|")
54
+ else
55
+ raise(ArgumentError, "Can only add row from a Hash or an Array but received #{row.class}")
56
+ end
57
+ end
58
+
59
+ # Removes a row from the example table. The row can be given as a Hash of
60
+ # parameters and their corresponding values or as an Array of values
61
+ # which will be assigned in order.
62
+ def remove_row(row)
63
+ case
64
+ when row.is_a?(Array)
65
+ location = @rows.index { |row_hash| row_hash.values_at(*@parameters) == row.collect { |value| value.strip } }
66
+ when row.is_a?(Hash)
67
+ location = @rows.index { |row_hash| row_hash == row.each_value { |value| value.strip! } }
68
+ else
69
+ raise(ArgumentError, "Can only remove row from a Hash or an Array but received #{row.class}")
70
+ end
71
+
72
+ #todo - remove once Hash rows are no longer supported
73
+ @rows.delete_at(location) if location
74
+ @row_elements.delete_at(location + 1) if location
75
+ end
76
+
77
+ # Returns the immediate child elements of the element.
78
+ def contains
79
+ @row_elements
80
+ end
81
+
82
+ # Returns a gherkin representation of the example.
83
+ def to_s
84
+ text = ''
85
+
86
+ text << tag_output_string + "\n" unless tags.empty?
87
+ text << "Examples:#{name_output_string}"
88
+ text << "\n" + description_output_string unless description_text.empty?
89
+ text << "\n" unless description_text.empty?
90
+ text << "\n" + parameters_output_string
91
+ text << "\n" + rows_output_string unless rows.empty?
92
+
93
+ text
94
+ end
95
+
96
+
97
+ private
98
+
99
+
100
+ def process_source(source)
101
+ case
102
+ when source.is_a?(String)
103
+ parse_example(source)
104
+ else
105
+ source
106
+ end
107
+ end
108
+
109
+ def parse_example(source_text)
110
+ base_file_string = "Feature: Fake feature to parse\nScenario Outline:\n* fake step\n"
111
+ source_text = base_file_string + source_text
112
+
113
+ parsed_file = Parsing::parse_text(source_text)
114
+
115
+ parsed_file.first['elements'].first['examples'].first
116
+ end
117
+
118
+ def build_example(parsed_example)
119
+ populate_element_tags(parsed_example)
120
+ populate_example_row_elements(parsed_example)
121
+ populate_example_parameters
122
+ populate_example_rows
123
+ end
124
+
125
+ def populate_example_parameters
126
+ @parameters = @row_elements.first.cells
127
+ end
128
+
129
+ def populate_example_rows
130
+ @row_elements.each do |row|
131
+ @rows << Hash[@parameters.zip(row.cells)]
132
+ end
133
+
134
+ @rows.shift
135
+ end
136
+
137
+ def populate_example_row_elements(parsed_example)
138
+ parsed_example['rows'].each do |row|
139
+ @row_elements << build_child_element(Row, row)
140
+ end
141
+ end
142
+
143
+ def determine_buffer_size(index)
144
+ row_elements.collect { |row| row.cells[index].length }.max || 0
145
+ end
146
+
147
+ def parameters_output_string
148
+ text = ''
149
+
150
+ unless parameters.empty?
151
+ text << " |"
152
+ parameters.count.times { |index| text << " #{string_for(parameters, index)} |" }
153
+ end
154
+
155
+ text
156
+ end
157
+
158
+ def rows_output_string
159
+ text = ''
160
+
161
+ unless rows.empty?
162
+
163
+ rows.each do |row|
164
+ text << " |"
165
+ row.values.count.times { |index| text << " #{string_for(ordered_row_values(row), index)} |" }
166
+ text << "\n"
167
+ end
168
+
169
+ text.chomp!
170
+ end
171
+
172
+ text
173
+ end
174
+
175
+ def string_for(cells, index)
176
+ cells[index] ? cells[index].ljust(determine_buffer_size(index)) : ''
177
+ end
178
+
179
+ def ordered_row_values(row_hash)
180
+ @parameters.collect { |parameter| row_hash[parameter] }
181
+ end
182
+
183
+ end
184
+ end
@@ -0,0 +1,147 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling a Cucumber Feature.
4
+
5
+ class Feature < FeatureElement
6
+
7
+ include Taggable
8
+ include Containing
9
+
10
+
11
+ # The Background object contained by the Feature
12
+ attr_accessor :background
13
+
14
+ # The TestElement objects contained by the Feature
15
+ attr_accessor :tests
16
+
17
+
18
+ # Creates a new Feature object and, if *source* is provided, populates the
19
+ # object.
20
+ def initialize(source = nil)
21
+ parsed_feature = process_source(source)
22
+
23
+ super(parsed_feature)
24
+
25
+ @tags = []
26
+ @tag_elements = []
27
+ @tests = []
28
+
29
+ build_feature(parsed_feature) if parsed_feature
30
+ end
31
+
32
+ # Returns true if the feature contains a background, false otherwise.
33
+ def has_background?
34
+ !@background.nil?
35
+ end
36
+
37
+ # Returns the scenarios contained in the feature.
38
+ def scenarios
39
+ @tests.select { |test| test.is_a? Scenario }
40
+ end
41
+
42
+ # Returns the outlines contained in the feature.
43
+ def outlines
44
+ @tests.select { |test| test.is_a? Outline }
45
+ end
46
+
47
+ # Returns the number of scenarios contained in the feature.
48
+ def scenario_count
49
+ scenarios.count
50
+ end
51
+
52
+ # Returns the number of outlines contained in the feature.
53
+ def outline_count
54
+ outlines.count
55
+ end
56
+
57
+ # Returns the number of tests contained in the feature.
58
+ def test_count
59
+ @tests.count
60
+ end
61
+
62
+ # Returns the number of test cases contained in the feature.
63
+ def test_case_count
64
+ scenario_count + outlines.reduce(0) { |outline_sum, outline|
65
+ outline_sum += outline.examples.reduce(0) { |example_sum, example|
66
+ example_sum += example.rows.count
67
+ }
68
+ }
69
+ end
70
+
71
+ # Returns the immediate child elements of the feature (i.e. its Background,
72
+ # Scenario, and Outline objects.
73
+ def contains
74
+ @background ? [@background] + @tests : @tests
75
+ end
76
+
77
+
78
+ # Returns gherkin representation of the feature.
79
+ def to_s
80
+ text = ''
81
+
82
+ text << tag_output_string + "\n" unless tags.empty?
83
+ text << "Feature:#{name_output_string}"
84
+ text << "\n" + description_output_string unless description_text.empty?
85
+ text << "\n\n" + background_output_string if background
86
+ text << "\n\n" + tests_output_string unless tests.empty?
87
+
88
+ text
89
+ end
90
+
91
+
92
+ private
93
+
94
+
95
+ def process_source(source)
96
+ case
97
+ when source.is_a?(String)
98
+ parse_feature(source)
99
+ else
100
+ source
101
+ end
102
+ end
103
+
104
+ def parse_feature(source_text)
105
+ parsed_file = Parsing::parse_text(source_text)
106
+
107
+ parsed_file.first
108
+ end
109
+
110
+ def build_feature(parsed_feature)
111
+ populate_element_tags(parsed_feature)
112
+ populate_feature_elements(parsed_feature)
113
+ end
114
+
115
+ def populate_feature_elements(parsed_feature)
116
+ elements = parsed_feature['elements']
117
+
118
+ if elements
119
+ elements.each do |element|
120
+ case element['keyword']
121
+ when 'Scenario'
122
+ @tests << build_child_element(Scenario, element)
123
+ when 'Scenario Outline'
124
+ @tests << build_child_element(Outline, element)
125
+ when 'Background'
126
+ @background = build_child_element(Background, element)
127
+ else
128
+ raise(ArgumentError, "Unknown keyword: #{element['keyword']}")
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def background_output_string
135
+ test_element_output_string(background)
136
+ end
137
+
138
+ def tests_output_string
139
+ tests.collect { |test| test_element_output_string(test) }.join("\n\n")
140
+ end
141
+
142
+ def test_element_output_string(test_element)
143
+ test_element.to_s.split("\n").collect { |line| line.empty? ? '' : " #{line}" }.join("\n")
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,73 @@
1
+ module CukeModeler
2
+
3
+ # A class modeling an basic element of a feature.
4
+
5
+ class FeatureElement
6
+
7
+ include Sourceable
8
+ include Raw
9
+ include Nested
10
+
11
+
12
+ # The name of the FeatureElement
13
+ attr_accessor :name
14
+
15
+ # Deprecated
16
+ #
17
+ # The description of the FeatureElement
18
+ attr_accessor :description
19
+
20
+ # The description of the FeatureElement
21
+ attr_accessor :description_text
22
+
23
+
24
+ # Creates a new FeatureElement object and, if *parsed_element* is provided,
25
+ # populates the object.
26
+ def initialize(parsed_element = nil)
27
+ @name = ''
28
+ @description = []
29
+ @description_text = ''
30
+
31
+ build_feature_element(parsed_element) if parsed_element
32
+ end
33
+
34
+
35
+ private
36
+
37
+
38
+ def build_feature_element(parsed_element)
39
+ populate_feature_element_name(parsed_element)
40
+ populate_feature_element_description(parsed_element)
41
+ populate_element_source_line(parsed_element)
42
+ populate_raw_element(parsed_element)
43
+ end
44
+
45
+ def populate_feature_element_name(parsed_element)
46
+ @name = parsed_element['name']
47
+ end
48
+
49
+ def populate_feature_element_description(parsed_element)
50
+ @description_text = parsed_element['description']
51
+ @description = parsed_element['description'].split("\n").collect { |line| line.strip }
52
+ @description.delete('')
53
+ end
54
+
55
+ def name_output_string
56
+ name.empty? ? '' : " #{name}"
57
+ end
58
+
59
+ def description_output_string
60
+ text = ''
61
+
62
+ unless description_text.empty?
63
+ description_lines = description_text.split("\n")
64
+
65
+ text << " \n" if description_lines.first =~ /\S/
66
+ text << description_lines.collect { |line| " #{line}" }.join("\n")
67
+ end
68
+
69
+ text
70
+ end
71
+
72
+ end
73
+ end