cql 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cql/dsl.rb +5 -0
- data/lib/cql/version.rb +1 -1
- data/testing/cucumber/features/clauses/from_clause.feature +0 -8
- data/testing/cucumber/features/clauses/predefined_with_filters.feature +392 -0
- data/testing/cucumber/features/clauses/select_clause.feature +1 -5
- data/testing/cucumber/features/clauses/with_clause.feature +2 -164
- data/testing/cucumber/features/dsl.feature +0 -22
- data/testing/cucumber/step_definitions/verification_steps.rb +5 -6
- data/testing/model_helper.rb +28 -0
- data/testing/rspec/spec/clauses/as_clause_spec.rb +1 -0
- data/testing/rspec/spec/clauses/from_clause_spec.rb +146 -0
- data/testing/rspec/spec/clauses/select_clause_spec.rb +184 -0
- data/testing/rspec/spec/clauses/transform_clause_spec.rb +35 -0
- data/testing/rspec/spec/clauses/with_clause_spec.rb +84 -0
- data/testing/rspec/spec/clauses/without_clause_spec.rb +171 -0
- data/testing/rspec/spec/dsl_spec.rb +3 -575
- data/testing/rspec/spec/filter_example_spec.rb +1 -1
- data/testing/rspec/spec/filter_feature_dsl_spec.rb +13 -13
- data/testing/rspec/spec/filter_sso_spec.rb +2 -2
- data/testing/rspec/spec/line_filterable_specs.rb +1 -1
- data/testing/rspec/spec/map_reduce_spec.rb +1 -1
- data/testing/rspec/spec/multiple_queries_spec.rb +1 -1
- data/testing/rspec/spec/name_filterable_specs.rb +1 -1
- data/testing/rspec/spec/predefined_filters_spec.rb +284 -0
- data/testing/rspec/spec/repository_spec.rb +3 -3
- data/testing/rspec/spec/select_feature_dsl_spec.rb +8 -8
- data/testing/rspec/spec/select_scen_outline_dsl_spec.rb +14 -14
- data/testing/rspec/spec/select_scenario_dsl_spec.rb +9 -9
- data/testing/rspec/spec/spec_helper.rb +3 -13
- metadata +21 -3
@@ -1,7 +1,7 @@
|
|
1
1
|
# todo - Rewrite the scenarios such that they use their own test specific feature files instead of setting up a large suite in the background
|
2
2
|
Feature: 'with' clause
|
3
3
|
|
4
|
-
The *with* clause specifies filter conditions that will reduce the number of things targeted by the *from* clause. The *with* clause can take one or more blocks that will filter out any object for which the block does not evaluate to true (using 'without' instead of 'with' will have the opposite effect). Alternatively, mappings of specific *from* targets to their respective filtering blocks can be provided. The *with* clause can also take predefined filters (
|
4
|
+
The *with* clause specifies filter conditions that will reduce the number of things targeted by the *from* clause. The *with* clause can take one or more blocks that will filter out any object for which the block does not evaluate to true (using 'without' instead of 'with' will have the opposite effect). Alternatively, mappings of specific *from* targets to their respective filtering blocks can be provided. The *with* clause can also take predefined filters (see corresponding documentation).
|
5
5
|
|
6
6
|
Sample usage:
|
7
7
|
````
|
@@ -9,41 +9,12 @@ Feature: 'with' clause
|
|
9
9
|
select name, tags, description_text
|
10
10
|
from features
|
11
11
|
with { |feature| feature.name =~ /foo/ }
|
12
|
-
with tc lt 3
|
13
12
|
end
|
14
13
|
````
|
15
14
|
|
16
15
|
This clause can be repeated multiple times. The arguments for successive clauses are simply added to the previous arguments.
|
17
16
|
|
18
17
|
|
19
|
-
The following filters are supported for models that have tags:
|
20
|
-
|
21
|
-
* tags - Filters out models that do not have the exact set of tags provided.
|
22
|
-
* tc - (tag count) Filters out models based on the number of tags that they have.
|
23
|
-
|
24
|
-
The following filters are supported for models that have names:
|
25
|
-
|
26
|
-
* name - Filters out models whose name does not match the name provided. Can be a string or regular expression.
|
27
|
-
|
28
|
-
The following filters are supported for models that have steps:
|
29
|
-
|
30
|
-
* line - Filters out models whose steps do not include the provided step (keywords and blocks are ignored). Can be a string or regular expression.
|
31
|
-
* lc - (line count) Filters out models based on the number of steps that they have.
|
32
|
-
|
33
|
-
The following filters are supported for feature models:
|
34
|
-
|
35
|
-
* sc - (scenario count) Filters out models based on the number of scenarios that they have.
|
36
|
-
* soc - (scenario outline count) Filters out models based on the number of outlines that they have.
|
37
|
-
* ssoc - (scenario and scenario outline count) Filters out models based on the total number of scenarios and outlines that they have.
|
38
|
-
|
39
|
-
For count based filters, the following operators are available:
|
40
|
-
|
41
|
-
* lt (Less than)
|
42
|
-
* lte (Less than or equals)
|
43
|
-
* gt (Greater than)
|
44
|
-
* gte (Greater than or equals)
|
45
|
-
|
46
|
-
|
47
18
|
Background: A sample Cucumber suite
|
48
19
|
Given a repository to query
|
49
20
|
And the following feature has been modeled in the repository:
|
@@ -161,7 +132,7 @@ Feature: 'with' clause
|
|
161
132
|
"""
|
162
133
|
select name
|
163
134
|
from features, scenarios
|
164
|
-
with scenarios =>
|
135
|
+
with scenarios => lambda { |element| element.name == 'Test 1' }
|
165
136
|
"""
|
166
137
|
Then the following values are returned:
|
167
138
|
| name |
|
@@ -216,127 +187,6 @@ Feature: 'with' clause
|
|
216
187
|
| A feature with lots of scenarios |
|
217
188
|
| A feature with lots of outlines |
|
218
189
|
|
219
|
-
# todo - break out the predefined filters into another feature file?
|
220
|
-
Scenario: Filtering by tags
|
221
|
-
When the following query is executed:
|
222
|
-
"""
|
223
|
-
select name
|
224
|
-
from scenarios
|
225
|
-
with tags '@tag_1', '@tag_2'
|
226
|
-
"""
|
227
|
-
Then the following values are returned:
|
228
|
-
| name |
|
229
|
-
| Test 1 |
|
230
|
-
|
231
|
-
Scenario: Filtering by tag count
|
232
|
-
When the following query is executed:
|
233
|
-
"""
|
234
|
-
select name
|
235
|
-
from scenarios, outlines
|
236
|
-
with tc gt 2
|
237
|
-
"""
|
238
|
-
Then the following values are returned:
|
239
|
-
| name |
|
240
|
-
| Test 3 |
|
241
|
-
|
242
|
-
Scenario: Filtering by name
|
243
|
-
When the following query is executed:
|
244
|
-
"""
|
245
|
-
select name
|
246
|
-
from scenarios, outlines
|
247
|
-
with name 'Test 3'
|
248
|
-
"""
|
249
|
-
Then the following values are returned:
|
250
|
-
| name |
|
251
|
-
| Test 3 |
|
252
|
-
When the following query is executed:
|
253
|
-
"""
|
254
|
-
select name
|
255
|
-
from scenarios, outlines
|
256
|
-
with name /Test [12]/
|
257
|
-
"""
|
258
|
-
Then the following values are returned:
|
259
|
-
| name |
|
260
|
-
| Test 1 |
|
261
|
-
| Test 2 |
|
262
|
-
|
263
|
-
Scenario: Filtering by line
|
264
|
-
When the following query is executed:
|
265
|
-
"""
|
266
|
-
select name
|
267
|
-
from scenarios, outlines
|
268
|
-
with line 'some steps'
|
269
|
-
"""
|
270
|
-
Then the following values are returned:
|
271
|
-
| name |
|
272
|
-
| Test 1 |
|
273
|
-
| Test 3 |
|
274
|
-
When the following query is executed:
|
275
|
-
"""
|
276
|
-
select name
|
277
|
-
from scenarios, outlines
|
278
|
-
with line /other/
|
279
|
-
"""
|
280
|
-
Then the following values are returned:
|
281
|
-
| name |
|
282
|
-
| Test 2 |
|
283
|
-
|
284
|
-
Scenario: Filtering by line count
|
285
|
-
When the following query is executed:
|
286
|
-
"""
|
287
|
-
select name
|
288
|
-
from scenarios, outlines
|
289
|
-
with lc gt 1
|
290
|
-
"""
|
291
|
-
Then the following values are returned:
|
292
|
-
| name |
|
293
|
-
| Test 3 |
|
294
|
-
|
295
|
-
Scenario: Filtering by scenario count
|
296
|
-
When the following query is executed:
|
297
|
-
"""
|
298
|
-
select name
|
299
|
-
from features
|
300
|
-
with sc gt 2
|
301
|
-
"""
|
302
|
-
Then the following values are returned:
|
303
|
-
| name |
|
304
|
-
| A feature with lots of scenarios |
|
305
|
-
|
306
|
-
Scenario: Filtering by outline count
|
307
|
-
When the following query is executed:
|
308
|
-
"""
|
309
|
-
select name
|
310
|
-
from features
|
311
|
-
with soc gt 2
|
312
|
-
"""
|
313
|
-
Then the following values are returned:
|
314
|
-
| name |
|
315
|
-
| A feature with lots of outlines |
|
316
|
-
|
317
|
-
Scenario: Filtering by combined test count
|
318
|
-
When the following query is executed:
|
319
|
-
"""
|
320
|
-
select name
|
321
|
-
from features
|
322
|
-
with ssoc lt 3
|
323
|
-
"""
|
324
|
-
Then the following values are returned:
|
325
|
-
| name |
|
326
|
-
| A feature with a mix of tests |
|
327
|
-
|
328
|
-
@wip
|
329
|
-
Scenario: Using the 'lt' count filter
|
330
|
-
|
331
|
-
@wip
|
332
|
-
Scenario: Using the 'lte' count filter
|
333
|
-
|
334
|
-
@wip
|
335
|
-
Scenario: Using the 'gt' count filter
|
336
|
-
|
337
|
-
@wip
|
338
|
-
Scenario: Using the 'gte' count filter
|
339
|
-
|
340
190
|
Scenario: Using 'without' for negation
|
341
191
|
When the following query is executed:
|
342
192
|
"""
|
@@ -350,15 +200,3 @@ Feature: 'with' clause
|
|
350
200
|
from scenarios
|
351
201
|
with { |scenario| !(scenario.source_line == 8) }
|
352
202
|
"""
|
353
|
-
When the following query is executed:
|
354
|
-
"""
|
355
|
-
select name
|
356
|
-
from features
|
357
|
-
without ssoc lt 3
|
358
|
-
"""
|
359
|
-
Then the result is the same as the result of the following query:
|
360
|
-
"""
|
361
|
-
select name
|
362
|
-
from features
|
363
|
-
with ssoc gt 2
|
364
|
-
"""
|
@@ -56,25 +56,3 @@ Feature: DSL
|
|
56
56
|
select 'name'
|
57
57
|
from 'scenarios'
|
58
58
|
"""
|
59
|
-
|
60
|
-
|
61
|
-
# Commented out so that they aren't picked up by Relish
|
62
|
-
#
|
63
|
-
# @wip
|
64
|
-
# Scenario: Use 'order_by' to sort the results
|
65
|
-
#
|
66
|
-
# # 'and' is a keyword. Some other kind of repeater word would be needed
|
67
|
-
# @wip
|
68
|
-
# Scenario: 'And' can be used instead of repeating the previous keyword
|
69
|
-
# When the following query is executed:
|
70
|
-
# """
|
71
|
-
# select 'name'
|
72
|
-
# and 'source_line'
|
73
|
-
# from CukeModeler::Scenario
|
74
|
-
# and CukeModeler::Outline
|
75
|
-
# """
|
76
|
-
# Then the following values are returned:
|
77
|
-
# | name | source_line |
|
78
|
-
# | Test 1 | 3 |
|
79
|
-
# | Test 2 | 6 |
|
80
|
-
# | Test 3 | 9 |
|
@@ -2,16 +2,15 @@ Then(/^the following values are returned:$/) do |values|
|
|
2
2
|
expected_keys = values.raw.first
|
3
3
|
expected_results = values.hashes
|
4
4
|
|
5
|
+
# Protecting against false positives
|
6
|
+
# Key order doesn't matter and Ruby 1.8.7 does not retain hash key ordering, so sorting them for consistency
|
7
|
+
raise('Invalid result set. Attribute names cannot be repeated.') unless expected_keys.sort == expected_results.first.keys.sort
|
8
|
+
|
5
9
|
expected_results.each do |result|
|
6
10
|
result.each_pair { |key, value| result[key] = value.to_i if value =~ /^\d+$/ }
|
7
11
|
end
|
8
12
|
|
9
|
-
|
10
|
-
@query_results.each_with_index do |result, index|
|
11
|
-
# Key order doesn't matter and Ruby 1.8.7 does not retain hash key ordering, so sorting them for consistency
|
12
|
-
expect(result.keys.sort).to eq(expected_keys.sort)
|
13
|
-
expect(result).to eq(expected_results[index])
|
14
|
-
end
|
13
|
+
expect(@query_results).to match_array(expected_results)
|
15
14
|
end
|
16
15
|
|
17
16
|
# Then(/^all of them can be queried for additional information$/) do
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CQL
|
2
|
+
module ModelHelper
|
3
|
+
|
4
|
+
def directory_with(*models)
|
5
|
+
directory_model = CukeModeler::Directory.new
|
6
|
+
|
7
|
+
models.each do |model|
|
8
|
+
case
|
9
|
+
when model.is_a?(CukeModeler::Feature)
|
10
|
+
file_model = CukeModeler::FeatureFile.new
|
11
|
+
|
12
|
+
if Gem.loaded_specs['cuke_modeler'].version.version[/^0/]
|
13
|
+
file_model.features = [model]
|
14
|
+
else
|
15
|
+
file_model.feature = model
|
16
|
+
end
|
17
|
+
|
18
|
+
directory_model.feature_files << file_model
|
19
|
+
else
|
20
|
+
raise(ArgumentError, "Don't know how to handle a '#{model.class}'")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
directory_model
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
#TODO - add some specs for the 'as' clause
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe 'an object that uses the DSL' do
|
5
|
+
|
6
|
+
|
7
|
+
let(:nodule) { CQL::Dsl }
|
8
|
+
let(:dsl_enabled_object) { Object.new.extend(nodule) }
|
9
|
+
|
10
|
+
|
11
|
+
describe "from" do
|
12
|
+
|
13
|
+
it 'knows from what to select attributes' do
|
14
|
+
expect(dsl_enabled_object).to respond_to(:from)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'selects from one or more things' do
|
18
|
+
expect(dsl_enabled_object.method(:from).arity).to eq(-1)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can handle an empty 'from' clause" do
|
22
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
23
|
+
|
24
|
+
result = gs.query do
|
25
|
+
select name
|
26
|
+
from
|
27
|
+
end
|
28
|
+
|
29
|
+
expect(result).to eq([])
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "multiple targets" do
|
33
|
+
|
34
|
+
it 'raises an exception for inapplicable attributes' do
|
35
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
36
|
+
|
37
|
+
expect {
|
38
|
+
gs.query do
|
39
|
+
select name, steps
|
40
|
+
from features
|
41
|
+
from scenarios
|
42
|
+
end
|
43
|
+
}.to raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'shorthand' do
|
49
|
+
|
50
|
+
it 'should consider an exact match over a pluralization' do
|
51
|
+
plural_class_model = CukeModeler::CqlTestModels.new
|
52
|
+
singular_class_model = CukeModeler::CqlTestModel.new
|
53
|
+
|
54
|
+
plural_class_model.attribute_1 = 'plural'
|
55
|
+
singular_class_model.attribute_1 = 'singular'
|
56
|
+
plural_class_model.children << singular_class_model
|
57
|
+
|
58
|
+
repo = CQL::Repository.new(plural_class_model)
|
59
|
+
|
60
|
+
result = repo.query do
|
61
|
+
select attribute_1
|
62
|
+
from cql_test_model
|
63
|
+
end
|
64
|
+
|
65
|
+
expect(result.first['attribute_1']).to eq('singular')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an exception if the shorthand form of a class cannot be mapped to a real class' do
|
69
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
70
|
+
|
71
|
+
expect {
|
72
|
+
gs.query do
|
73
|
+
select name
|
74
|
+
from not_a_real_class
|
75
|
+
end
|
76
|
+
}.to raise_error(ArgumentError, "Class 'CukeModeler::NotARealClass' does not exist")
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'can freely mix shorthand and long-form names' do
|
81
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
82
|
+
|
83
|
+
# All long-form
|
84
|
+
base_result = gs.query do
|
85
|
+
select name
|
86
|
+
from CukeModeler::Scenario, CukeModeler::Feature
|
87
|
+
end
|
88
|
+
|
89
|
+
# All shorthand
|
90
|
+
expect(
|
91
|
+
gs.query do
|
92
|
+
select name
|
93
|
+
from scenarios, features
|
94
|
+
end
|
95
|
+
).to eq(base_result)
|
96
|
+
|
97
|
+
# A mix of both
|
98
|
+
expect(
|
99
|
+
gs.query do
|
100
|
+
select name
|
101
|
+
from CukeModeler::Scenario, features
|
102
|
+
end
|
103
|
+
).to eq(base_result)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
describe 'special scopes' do
|
110
|
+
|
111
|
+
it 'understands the :all scope' do
|
112
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
113
|
+
|
114
|
+
expect { gs.query do
|
115
|
+
select :model
|
116
|
+
from :all
|
117
|
+
end
|
118
|
+
}.to_not raise_error
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'queries from all models when scoped to :all' do
|
122
|
+
model_1 = CukeModeler::CqlTestModel.new
|
123
|
+
model_2 = CukeModeler::CqlTestModel.new
|
124
|
+
model_3 = CukeModeler::CqlTestModel.new
|
125
|
+
|
126
|
+
model_1.children << model_2
|
127
|
+
model_1.children << model_3
|
128
|
+
|
129
|
+
repo = CQL::Repository.new(model_1)
|
130
|
+
|
131
|
+
result = repo.query do
|
132
|
+
select :model
|
133
|
+
from :all
|
134
|
+
end
|
135
|
+
|
136
|
+
expect(result).to match_array([{:model => model_1},
|
137
|
+
{:model => model_2},
|
138
|
+
{:model => model_3}])
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe 'an object that uses the DSL' do
|
5
|
+
|
6
|
+
|
7
|
+
let(:nodule) { CQL::Dsl }
|
8
|
+
let(:dsl_enabled_object) { Object.new.extend(nodule) }
|
9
|
+
|
10
|
+
describe "select" do
|
11
|
+
|
12
|
+
it 'knows how to select attributes' do
|
13
|
+
expect(dsl_enabled_object).to respond_to(:select)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'selects one or more attributes' do
|
17
|
+
expect(dsl_enabled_object.method(:select).arity).to eq(-1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'correctly selects a single attribute from a model' do
|
21
|
+
model = CukeModeler::CqlTestModel.new
|
22
|
+
model.attribute_1 = 'foo'
|
23
|
+
|
24
|
+
repo = CQL::Repository.new(model)
|
25
|
+
|
26
|
+
result = repo.query do
|
27
|
+
select attribute_1
|
28
|
+
from cql_test_model
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
expect(result).to eq([{'attribute_1' => 'foo'}])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'correctly selects multiple attributes from a model' do
|
36
|
+
model = CukeModeler::CqlTestModel.new
|
37
|
+
model.attribute_1 = 'foo'
|
38
|
+
model.attribute_2 = 'bar'
|
39
|
+
|
40
|
+
repo = CQL::Repository.new(model)
|
41
|
+
|
42
|
+
result = repo.query do
|
43
|
+
select attribute_1, attribute_2
|
44
|
+
from cql_test_model
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
expect(result).to eq([{'attribute_1' => 'foo',
|
49
|
+
'attribute_2' => 'bar'}])
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
describe 'special attributes' do
|
54
|
+
|
55
|
+
it 'understands the :model attribute' do
|
56
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
57
|
+
|
58
|
+
expect { gs.query do
|
59
|
+
select :model
|
60
|
+
from features
|
61
|
+
end
|
62
|
+
}.to_not raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'interprets :model in the same manner that it interprets :self' do
|
66
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
67
|
+
|
68
|
+
self_result = gs.query do
|
69
|
+
select :self
|
70
|
+
from features
|
71
|
+
end
|
72
|
+
|
73
|
+
model_result = gs.query do
|
74
|
+
select :model
|
75
|
+
from features
|
76
|
+
end
|
77
|
+
|
78
|
+
# Only checking the values of the results because they will have different :model/:self keys
|
79
|
+
expect(model_result.collect { |result| result.values }).to eq(self_result.collect { |result| result.values })
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'complains if an unknown special attribute is queried' do
|
83
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
84
|
+
|
85
|
+
expect {
|
86
|
+
gs.query do
|
87
|
+
select :foo
|
88
|
+
from scenarios
|
89
|
+
end
|
90
|
+
}.to raise_error(ArgumentError, ":foo is not a valid attribute for selection.")
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'uses the :self attribute by default' do
|
94
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
95
|
+
|
96
|
+
default_result = gs.query do
|
97
|
+
select
|
98
|
+
from features
|
99
|
+
end
|
100
|
+
|
101
|
+
self_result = gs.query do
|
102
|
+
select :self
|
103
|
+
from features
|
104
|
+
end
|
105
|
+
|
106
|
+
expect(self_result).to eq(default_result)
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
it 'complains if an unknown normal attribute is queried' do
|
113
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
114
|
+
|
115
|
+
expect {
|
116
|
+
gs.query do
|
117
|
+
select steps
|
118
|
+
from features
|
119
|
+
end
|
120
|
+
}.to raise_error(ArgumentError, "'steps' is not a valid attribute for selection from a 'CukeModeler::Feature'.")
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
describe "multiple selections" do
|
125
|
+
|
126
|
+
it 'can freely mix empty selections and attribute selections' do
|
127
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
128
|
+
|
129
|
+
base_result = gs.query do
|
130
|
+
select :self
|
131
|
+
select name
|
132
|
+
select :self
|
133
|
+
as 'foo', 'bar', 'baz'
|
134
|
+
from scenarios
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
expect(
|
139
|
+
gs.query do
|
140
|
+
select
|
141
|
+
select name
|
142
|
+
select
|
143
|
+
as 'foo', 'bar', 'baz'
|
144
|
+
from scenarios
|
145
|
+
end
|
146
|
+
).to eq(base_result)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
describe 'duplicate selections' do
|
153
|
+
|
154
|
+
let(:warning_message) { "Multiple selections made without using an 'as' clause\n" }
|
155
|
+
|
156
|
+
it "warns if the same attribute is selected more than once without an 'as' clause being used" do
|
157
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
158
|
+
|
159
|
+
expect {
|
160
|
+
gs.query do
|
161
|
+
select :model, :model, :model
|
162
|
+
from :all
|
163
|
+
end
|
164
|
+
}.to output(warning_message).to_stderr
|
165
|
+
end
|
166
|
+
|
167
|
+
it "does not warn if the same attribute is selected more than once and an 'as' clause is used" do
|
168
|
+
gs = CQL::Repository.new("#{CQL_FEATURE_FIXTURES_DIRECTORY}/scenario/simple")
|
169
|
+
|
170
|
+
expect {
|
171
|
+
gs.query do
|
172
|
+
select :model, :model, :model
|
173
|
+
# Usage of the clause is sufficient. Not going to try and count the mappings or anything like that.
|
174
|
+
as foo
|
175
|
+
from :all
|
176
|
+
end
|
177
|
+
}.to_not output(warning_message).to_stderr
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|