cql 0.1.0 → 0.1.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.
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + "/map_reduce"
2
+ module CQL
3
+ DSL_KEYWORDS = %w(features scenario_outlines scenarios all step_lines examples name)
4
+ module Dsl
5
+ (CQL::QUERY_VALUES + CQL::DSL_KEYWORDS).each do |method_name|
6
+ define_method(method_name) { |*args|
7
+ return method_name if args.size == 0
8
+ {method_name=>args}
9
+ }
10
+ end
11
+
12
+ %w(sc_gt sc_gte sc_lt sc_lte soc_gt soc_gte soc_lt soc_lte ssoc_gt ssoc_gte ssoc_lt ssoc_lte tc_lt tc_lte tc_gt tc_gte lc_lt lc_lte lc_gt lc_gte).each do |meth|
13
+ define_method(meth) { |num| {meth=>num} }
14
+ end
15
+
16
+ alias :everything :all
17
+ alias :complete :all
18
+
19
+ def select *what
20
+ @what = what
21
+ end
22
+
23
+ def from where
24
+ @from = where
25
+ @data
26
+ end
27
+
28
+ def tags *tags
29
+ return "tags" if tags.size == 0
30
+ {'tags'=>tags}
31
+ end
32
+
33
+ def with filter
34
+ if filter.has_key? 'name'
35
+ @data = CQL::MapReduce.filter_features(@data, 'feature'=>filter['name'])
36
+ elsif @from == 'features'
37
+ filter.each { |k, v| @data = CQL::MapReduce.filter_features(@data, k=>v) }
38
+ elsif @from == 'scenarios'
39
+ filter.each { |k, v|
40
+ @data = CQL::MapReduce.filter_sso2(@data, k=>v)
41
+ }
42
+ end
43
+ @data
44
+ end
45
+
46
+ class Query
47
+ include Dsl
48
+ attr_reader :data, :what
49
+
50
+ def initialize features, &block
51
+ @data = features
52
+ @data = self.instance_eval(&block)
53
+
54
+ @data= CQL::MapReduce.filter_sso(@data, 'what'=>@from[0, @from.size-1]) if @from != "features"
55
+ result = Array.new(@data.size)
56
+ result = result.map {|e|{}}
57
+ @what.each do |w|
58
+ CQL::MapReduce.send(w, @data).each_with_index { |e, i| result[i][w]=e }
59
+ end
60
+ @data = result.size == 1 ? result.first : result
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,139 @@
1
+ require File.dirname(__FILE__) + "/dsl"
2
+ require 'set'
3
+ module CQL
4
+ QUERY_VALUES = %w(name uri line description type steps id tags examples)
5
+
6
+ class MapReduce
7
+ CQL::QUERY_VALUES.each do |property|
8
+ define_singleton_method(property) do |input|
9
+ input = [input] if input.class != Array
10
+ input.map { |a| a[property] }
11
+ end
12
+ end
13
+
14
+ %w(all everything complete).each do |method_name|
15
+ define_singleton_method(method_name) { |input| input }
16
+ end
17
+
18
+ def self.step_lines input
19
+ input = [input] if input.class != Array
20
+ steps(input).map do |scen|
21
+ scen.map { |line| line['keyword'] + line['name'] }
22
+ end
23
+ end
24
+
25
+ def self.filter_features input, args
26
+ if args.has_key?('feature') && args['feature'][0].class == String
27
+ input = input.find_all { |feature| feature['name'] == args['feature'][0] }
28
+ elsif args.has_key?('feature') && args['feature'][0].class == Regexp
29
+ input = input.find_all { |feature| feature['name'] =~ args['feature'][0] }
30
+ end
31
+
32
+ %w(sc_gt sc_gte sc_lt sc_lte soc_gt soc_gte soc_lt soc_lte ssoc_gt ssoc_gte ssoc_lt ssoc_lte).each do |fn|
33
+ if args.has_key?(fn)
34
+ what, operator = fn.split "_"
35
+ desc = {"sc"=>["Scenario"], "soc"=>["Scenario Outline"], "ssoc"=>["Scenario", "Scenario Outline"]}
36
+ operator_map = {"lt"=>'<', 'lte'=>'<=', 'gt'=>'>', 'gte'=>'>='}
37
+ input = input.find_all do |feature|
38
+ size = feature['elements'].find_all { |e| desc[what].include? e['keyword'] }.size
39
+ size.send(operator_map[operator], args[fn])
40
+ end
41
+ end
42
+ end
43
+
44
+ %w(tc_lt tc_lte tc_gt tc_gte).each do |fn|
45
+ what, operator = fn.split "_"
46
+ operator_map = {"lt"=>'<', 'lte'=>'<=', 'gt'=>'>', 'gte'=>'>='}
47
+ if args.has_key?(fn)
48
+ input = input.find_all do |feature|
49
+ feature['tags'] && feature['tags'].size.send(operator_map[operator], args[fn])
50
+ end
51
+ end
52
+ end
53
+
54
+ input = input.find_all { |feature| has_tags feature['tags'], args['tags'] } if args.has_key? 'tags'
55
+ input
56
+ end
57
+
58
+ def self.filter_sso input, args
59
+ results = []
60
+ input = filter_features(input, 'feature'=>args['feature']) if args.has_key?('feature')
61
+ input.each do |feature|
62
+ feature['elements'].each do |element|
63
+ results.push element if element['type'] == args['what']
64
+ end
65
+ end
66
+ results
67
+ end
68
+
69
+ def self.filter_sso2 input, args
70
+ %w(tc_lt tc_lte tc_gt tc_gte).each do |fn|
71
+ what, operator = fn.split "_"
72
+ operator_map = {"lt"=>'<', 'lte'=>'<=', 'gt'=>'>', 'gte'=>'>='}
73
+ if args.has_key?(fn)
74
+ input.each_with_index do |feature, index|
75
+ filtered_elements= feature['elements'].find_all do |sso|
76
+ sso['tags'].size.send(operator_map[operator], args[fn])
77
+ end
78
+ input[index]['elements'] = filtered_elements
79
+
80
+ end
81
+ end
82
+ end
83
+
84
+ %w(lc_lt lc_lte lc_gt lc_gte).each do |fn|
85
+ what, operator = fn.split "_"
86
+ operator_map = {"lt"=>'<', 'lte'=>'<=', 'gt'=>'>', 'gte'=>'>='}
87
+ if args.has_key?(fn)
88
+ input.each_with_index do |feature, index|
89
+ filtered_elements= feature['elements'].find_all do |sso|
90
+ sso['steps'].size.send(operator_map[operator], args[fn])
91
+ end
92
+ input[index]['elements'] = filtered_elements
93
+ end
94
+ end
95
+ end
96
+
97
+ if args.has_key? 'line'
98
+ input.each_with_index do |feature, index|
99
+ filtered_elements= feature['elements'].find_all do |sso|
100
+ raw_step_lines = sso['steps'].map { |sl| sl['name'] }
101
+ line_to_match = args['line'].first
102
+ result = nil
103
+ if line_to_match.class == String
104
+ result = raw_step_lines.include? line_to_match
105
+ elsif line_to_match.class == Regexp
106
+ result = raw_step_lines.find { |line| line =~ line_to_match }
107
+ if result.class == String
108
+ result = result.size > 0
109
+ else
110
+ result = false
111
+ end
112
+ end
113
+ result
114
+ end
115
+ input[index]['elements'] = filtered_elements
116
+ end
117
+ end
118
+
119
+ input
120
+ end
121
+
122
+ def self.tag_set input
123
+ tags = Set.new
124
+ input.each do |feature|
125
+ feature['elements'].each do |element|
126
+ break if element['tags'] == nil
127
+ element['tags'].each { |tag| tags.add tag['name'] }
128
+ end
129
+ end
130
+ tags.to_a
131
+ end
132
+
133
+ def self.has_tags given, search
134
+ return false if given == nil
135
+ search.count { |tag_for_search| given.map { |t| t["name"] }.include?(tag_for_search) }==search.size
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,34 @@
1
+ require 'gherkin/parser/parser'
2
+ require 'gherkin/formatter/json_formatter'
3
+ require 'stringio'
4
+ require File.dirname(__FILE__) + "/dsl"
5
+
6
+ module CQL
7
+ class Repository
8
+ include Dsl
9
+ attr_reader :parsed_feature_files
10
+
11
+ def initialize features_home_dir
12
+ @parsed_feature_files = load_features(list_features(features_home_dir))
13
+ end
14
+
15
+ def query &block
16
+ Query.new(parsed_feature_files.clone, &block).data
17
+ end
18
+
19
+ private
20
+ def list_features base_dir
21
+ Dir.glob(base_dir + "/**/*.feature")
22
+ end
23
+
24
+ def load_features sources
25
+ io = StringIO.new
26
+ formatter = Gherkin::Formatter::JSONFormatter.new(io)
27
+ parser = Gherkin::Parser::Parser.new(formatter)
28
+ sources.each { |s| parser.parse(IO.read(s), s, 0) }
29
+ formatter.done
30
+ JSON.parse(io.string)
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,486 @@
1
+ require 'rspec'
2
+ require File.dirname(__FILE__) + "/../lib/repo"
3
+
4
+ describe "cql" do
5
+
6
+ describe 'scenario outline and scenario count functions' do
7
+ it 'should filter based on the number of scenarios for ssoc_gt' do
8
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
9
+
10
+ result = gs.query do
11
+ select name
12
+ from features
13
+ with ssoc_gt 5
14
+ end
15
+
16
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
17
+ {"name"=> "f2_7_scenarios_2_so"}]
18
+ end
19
+
20
+ it 'should filter based on the number of scenario outlines for ssoc_gte' do
21
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
22
+
23
+ result = gs.query do
24
+ select name
25
+ from features
26
+ with ssoc_gte 5
27
+ end
28
+
29
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
30
+ {"name"=> "f2_7_scenarios_2_so"},
31
+ {"name"=> "f3_2_scenarios_3_so"}]
32
+
33
+ result = gs.query do
34
+ select name
35
+ from features
36
+ with ssoc_gte 9
37
+ end
38
+
39
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
40
+ {"name"=> "f2_7_scenarios_2_so"}]
41
+
42
+ result = gs.query do
43
+ select name
44
+ from features
45
+ with soc_gte 1
46
+ end
47
+
48
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
49
+ {"name"=> "f2_7_scenarios_2_so"},
50
+ {"name"=> "f3_2_scenarios_3_so"}]
51
+
52
+ result = gs.query do
53
+ select name
54
+ from features
55
+ with soc_gte 10
56
+ end
57
+
58
+ result.should == []
59
+ end
60
+
61
+ it 'should filter based on the number of scenarios for ssoc_lt' do
62
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
63
+
64
+ result = gs.query do
65
+ select name
66
+ from features
67
+ with ssoc_lt 10
68
+ end
69
+
70
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
71
+ {"name"=> "f2_7_scenarios_2_so"},
72
+ {"name"=> "f3_2_scenarios_3_so"}]
73
+
74
+ result = gs.query do
75
+ select name
76
+ from features
77
+ with ssoc_lt 9
78
+ end
79
+
80
+ result.should == {"name"=> "f3_2_scenarios_3_so"}
81
+
82
+ result = gs.query do
83
+ select name
84
+ from features
85
+ with ssoc_lt 3
86
+ end
87
+
88
+ result.should == []
89
+ end
90
+
91
+ it 'should filter based on the number of scenarios for ssoc_lte' do
92
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
93
+
94
+ result = gs.query do
95
+ select name
96
+ from features
97
+ with ssoc_lte 10
98
+ end
99
+
100
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
101
+ {"name"=>"f2_7_scenarios_2_so"},
102
+ {"name"=> "f3_2_scenarios_3_so"}]
103
+
104
+ result = gs.query do
105
+ select name
106
+ from features
107
+ with ssoc_lte 9
108
+ end
109
+
110
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
111
+ {"name"=>"f2_7_scenarios_2_so"},
112
+ {"name"=> "f3_2_scenarios_3_so"}]
113
+
114
+ result = gs.query do
115
+ select name
116
+ from features
117
+ with ssoc_lte 5
118
+ end
119
+
120
+ result.should == {"name"=> "f3_2_scenarios_3_so"}
121
+
122
+
123
+ result = gs.query do
124
+ select name
125
+ from features
126
+ with ssoc_lte 4
127
+ end
128
+
129
+ result.should == []
130
+ end
131
+
132
+ end
133
+
134
+
135
+ describe 'scenario count functions' do
136
+ it 'should filter based on the number of scenarios for sc_gt' do
137
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
138
+
139
+ result = gs.query do
140
+ select name
141
+ from features
142
+ with sc_gt 2
143
+ end
144
+
145
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
146
+ {"name"=> "f2_7_scenarios_2_so"}]
147
+ end
148
+
149
+ it 'should filter based on the number of scenarios for sc_gte' do
150
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
151
+
152
+ result = gs.query do
153
+ select name
154
+ from features
155
+ with sc_gte 2
156
+ end
157
+
158
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
159
+ {"name"=> "f2_7_scenarios_2_so"},
160
+ {"name"=> "f3_2_scenarios_3_so"}]
161
+
162
+ result = gs.query do
163
+ select name
164
+ from features
165
+ with sc_gte 4
166
+ end
167
+
168
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
169
+ {"name"=> "f2_7_scenarios_2_so"}]
170
+
171
+ result = gs.query do
172
+ select name
173
+ from features
174
+ with sc_gte 3
175
+ end
176
+
177
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
178
+ {"name"=> "f2_7_scenarios_2_so"}]
179
+
180
+ result = gs.query do
181
+ select name
182
+ from features
183
+ with sc_gte 7
184
+ end
185
+
186
+ result.should == {"name"=> "f2_7_scenarios_2_so"}
187
+ end
188
+
189
+ it 'should filter based on the number of scenarios for sc_lt' do
190
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
191
+
192
+ result = gs.query do
193
+ select name
194
+ from features
195
+ with sc_lt 7
196
+ end
197
+
198
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
199
+ {"name"=> "f3_2_scenarios_3_so"}]
200
+
201
+ result = gs.query do
202
+ select name
203
+ from features
204
+ with sc_lt 5
205
+ end
206
+
207
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
208
+ {"name"=> "f3_2_scenarios_3_so"}]
209
+
210
+ result = gs.query do
211
+ select name
212
+ from features
213
+ with sc_lt 4
214
+ end
215
+
216
+ result.should == {"name"=> "f3_2_scenarios_3_so"}
217
+ end
218
+
219
+ it 'should filter based on the number of scenarios for sc_lte' do
220
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
221
+
222
+ result = gs.query do
223
+ select name
224
+ from features
225
+ with sc_lte 7
226
+ end
227
+
228
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
229
+ {"name"=>"f2_7_scenarios_2_so"},
230
+ {"name"=> "f3_2_scenarios_3_so"}]
231
+
232
+ result = gs.query do
233
+ select name
234
+ from features
235
+ with sc_lte 5
236
+ end
237
+
238
+ result.should == [{"name"=> "f1_4_scenarios_5_so"},
239
+ {"name"=> "f3_2_scenarios_3_so"}]
240
+
241
+ result = gs.query do
242
+ select name
243
+ from features
244
+ with sc_lte 4
245
+ end
246
+
247
+ result.should == [{"name"=> "f1_4_scenarios_5_so"}, {"name"=> "f3_2_scenarios_3_so"}]
248
+ end
249
+
250
+ it 'should filter on the number of tags on a feature' do
251
+
252
+ end
253
+ end
254
+
255
+ describe 'filter by tag count' do
256
+
257
+ {
258
+ 0=>[],
259
+ 1=>[],
260
+ 2=>{"name"=> "f1_1_tag"},
261
+ 3=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}],
262
+ 4=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
263
+ 5=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}]
264
+
265
+ }.each do |number, expected|
266
+ it "should filter features by the number of tags with the 'tc_lt' operator for count of #{number}" do
267
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/b"
268
+
269
+ result = gs.query do
270
+ select name
271
+ from features
272
+ with tc_lt number
273
+ end
274
+
275
+ result.should == expected
276
+ end
277
+ end
278
+
279
+ {
280
+ 0=>[],
281
+ 1=>{"name"=> "f1_1_tag"},
282
+ 2=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}],
283
+ 3=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
284
+ 4=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}]
285
+
286
+ }.each do |number, expected|
287
+ it "should filter features by the number of tags with the 'tc_lte' operator for count of #{number}" do
288
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/b"
289
+
290
+ result = gs.query do
291
+ select name
292
+ from features
293
+ with tc_lte number
294
+ end
295
+
296
+ result.should == expected
297
+ end
298
+ end
299
+
300
+ {
301
+ 0=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
302
+ 1=>[{"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
303
+ 2=>{"name"=> "f3_3_tags"},
304
+ 3=>[],
305
+ 4=>[]
306
+
307
+ }.each do |number, expected|
308
+ it "should filter features by the number of tags with the 'tc_gt' operator for count of #{number}" do
309
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/b"
310
+
311
+ result = gs.query do
312
+ select name
313
+ from features
314
+ with tc_gt number
315
+ end
316
+
317
+ result.should == expected
318
+ end
319
+ end
320
+
321
+ {
322
+ 0=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
323
+ 1=>[{"name"=> "f1_1_tag"}, {"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
324
+ 2=>[{"name"=> "f2_2_tags"}, {"name"=> "f3_3_tags"}],
325
+ 3=>{"name"=> "f3_3_tags"},
326
+ 4=>[],
327
+ 5=>[]
328
+
329
+ }.each do |number, expected|
330
+ it "should filter features by the number of tags with the 'tc_gte' operator for count of #{number}" do
331
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/b"
332
+
333
+ result = gs.query do
334
+ select name
335
+ from features
336
+ with tc_gte number
337
+ end
338
+
339
+ result.should == expected
340
+ end
341
+ end
342
+
343
+ end
344
+
345
+ describe 'scenario outline count functions' do
346
+ {
347
+ 2=>[{"name"=> "f1_4_scenarios_5_so"}, {"name"=> "f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
348
+ 3=>[{"name"=> "f1_4_scenarios_5_so"}, {"name"=> "f3_2_scenarios_3_so"}],
349
+ 4=>{"name"=> "f1_4_scenarios_5_so"},
350
+ 7=>[]
351
+
352
+ }.each do |number, expected|
353
+ it "soc_gte filter should filter scenarios for input '#{number}'" do
354
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
355
+
356
+ result = gs.query do
357
+ select name
358
+ from features
359
+ with soc_gte number
360
+ end
361
+
362
+ result.should == expected
363
+ end
364
+ end
365
+
366
+ {
367
+ 7=>[{"name"=> "f1_4_scenarios_5_so"}, {"name"=> "f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
368
+ 5=>[{"name"=> "f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
369
+ 4=>[{"name"=> "f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
370
+
371
+ }.each do |number, expected|
372
+ it "soc_lt filter should filter scenarios for input '#{number}'" do
373
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
374
+ result = gs.query do
375
+ select name
376
+ from features
377
+ with soc_lt number
378
+ end
379
+
380
+ result.should == expected
381
+ end
382
+ end
383
+
384
+
385
+ {
386
+ 7=>[{"name"=> "f1_4_scenarios_5_so"}, {"name"=>"f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
387
+ 5=>[{"name"=> "f1_4_scenarios_5_so"}, {"name"=>"f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
388
+ 4=>[{"name"=> "f2_7_scenarios_2_so"}, {"name"=> "f3_2_scenarios_3_so"}],
389
+ }.each do |num, expected|
390
+ it "should filter based on the number of scenarios for soc_lte with input '#{num}'" do
391
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/combined/a"
392
+
393
+ result = gs.query do
394
+ select name
395
+ from features
396
+ with soc_lte num
397
+ end
398
+
399
+ result.should == expected
400
+ end
401
+ end
402
+ end
403
+
404
+
405
+ describe 'filter features by name' do
406
+ it 'should filter by name' do
407
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/scenario/tagged_features"
408
+
409
+ result = gs.query do
410
+ select name
411
+ from features
412
+ with name 'Test2 Feature'
413
+ end
414
+
415
+ result.should == {"name"=> "Test2 Feature"}
416
+ end
417
+
418
+ it 'should filter by name regexp' do
419
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/scenario/tagged_features"
420
+
421
+ result = gs.query do
422
+ select name
423
+ from features
424
+ with name /Test2 Feature/
425
+ end
426
+
427
+ result.should == {"name"=> "Test2 Feature"}
428
+
429
+ result = gs.query do
430
+ select name
431
+ from features
432
+ with name /Feature/
433
+ end
434
+
435
+ result.size.should == 3
436
+ end
437
+ end
438
+
439
+ describe 'filter features by tag' do
440
+ it 'should filter by a single tag' do
441
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/scenario/tagged_features"
442
+
443
+ result = gs.query do
444
+ select name
445
+ from features
446
+ with tags '@one'
447
+ end
448
+
449
+ result.should == [{"name"=> "Test Feature"}, {"name"=>"Test3 Feature"}]
450
+
451
+ result = gs.query do
452
+ select name
453
+ from features
454
+ with tags '@two'
455
+ end
456
+
457
+ result.should == [{"name"=> "Test2 Feature"}, {"name"=>"Test3 Feature"}]
458
+ end
459
+
460
+ it 'should filter by multiple filters' do
461
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/scenario/tagged_features"
462
+
463
+ result = gs.query do
464
+ select name
465
+ from features
466
+ with tags '@two'
467
+ with tags '@one'
468
+ end
469
+
470
+ result.should == {"name"=>"Test3 Feature"}
471
+ end
472
+
473
+ it 'should filter by a multiple tags' do
474
+ gs = CQL::Repository.new File.dirname(__FILE__) + "/../fixtures/features/scenario/tagged_features"
475
+
476
+ result = gs.query do
477
+ select name
478
+ from features
479
+ with tags '@one', '@two'
480
+ end
481
+
482
+ result.should == {"name"=>"Test3 Feature"}
483
+ end
484
+ end
485
+
486
+ end