activefacts 0.8.9 → 0.8.10
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.
- data/.gemtest +0 -0
- data/Manifest.txt +28 -33
- data/Rakefile +11 -12
- data/bin/cql +90 -46
- data/examples/CQL/Blog.cql +2 -1
- data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
- data/examples/CQL/Death.cql +1 -1
- data/examples/CQL/Diplomacy.cql +9 -9
- data/examples/CQL/Genealogy.cql +3 -2
- data/examples/CQL/Insurance.cql +10 -7
- data/examples/CQL/JoinEquality.cql +2 -2
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +73 -53
- data/examples/CQL/MetamodelNext.cql +89 -67
- data/examples/CQL/OneToOnes.cql +2 -2
- data/examples/CQL/ServiceDirector.cql +10 -5
- data/examples/CQL/Supervision.cql +3 -3
- data/examples/CQL/Tests.Test5.Load.cql +1 -1
- data/examples/CQL/Warehousing.cql +4 -2
- data/lib/activefacts/cql/CQLParser.treetop +26 -60
- data/lib/activefacts/cql/Context.treetop +12 -2
- data/lib/activefacts/cql/Expressions.treetop +14 -30
- data/lib/activefacts/cql/FactTypes.treetop +165 -110
- data/lib/activefacts/cql/Language/English.treetop +167 -54
- data/lib/activefacts/cql/LexicalRules.treetop +16 -2
- data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
- data/lib/activefacts/cql/Terms.treetop +57 -27
- data/lib/activefacts/cql/ValueTypes.treetop +39 -13
- data/lib/activefacts/cql/compiler.rb +5 -3
- data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
- data/lib/activefacts/cql/compiler/constraint.rb +178 -275
- data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
- data/lib/activefacts/cql/compiler/expression.rb +418 -0
- data/lib/activefacts/cql/compiler/fact.rb +146 -145
- data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
- data/lib/activefacts/cql/compiler/join.rb +159 -0
- data/lib/activefacts/cql/compiler/shared.rb +51 -23
- data/lib/activefacts/cql/compiler/value_type.rb +56 -2
- data/lib/activefacts/cql/parser.rb +15 -4
- data/lib/activefacts/generate/absorption.rb +7 -7
- data/lib/activefacts/generate/cql.rb +100 -37
- data/lib/activefacts/generate/oo.rb +28 -51
- data/lib/activefacts/generate/ordered.rb +60 -36
- data/lib/activefacts/generate/ruby.rb +6 -6
- data/lib/activefacts/generate/sql/server.rb +4 -4
- data/lib/activefacts/input/orm.rb +71 -53
- data/lib/activefacts/persistence.rb +1 -1
- data/lib/activefacts/persistence/columns.rb +27 -23
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +17 -17
- data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
- data/lib/activefacts/persistence/reference.rb +61 -36
- data/lib/activefacts/persistence/tables.rb +61 -59
- data/lib/activefacts/support.rb +54 -29
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +99 -54
- data/lib/activefacts/vocabulary/metamodel.rb +43 -37
- data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
- data/spec/absorption_spec.rb +8 -8
- data/spec/cql/comparison_spec.rb +91 -0
- data/spec/cql/contractions_spec.rb +251 -0
- data/spec/cql/entity_type_spec.rb +319 -0
- data/spec/cql/expressions_spec.rb +63 -0
- data/spec/cql/fact_type_matching_spec.rb +283 -0
- data/spec/cql/french_spec.rb +21 -0
- data/spec/cql/parser/bad_literals_spec.rb +86 -0
- data/spec/cql/parser/constraints_spec.rb +19 -0
- data/spec/cql/parser/entity_types_spec.rb +106 -0
- data/spec/cql/parser/expressions_spec.rb +179 -0
- data/spec/cql/parser/fact_types_spec.rb +41 -0
- data/spec/cql/parser/literals_spec.rb +312 -0
- data/spec/cql/parser/pragmas_spec.rb +89 -0
- data/spec/cql/parser/value_types_spec.rb +42 -0
- data/spec/cql/role_matching_spec.rb +147 -0
- data/spec/cql/samples_spec.rb +9 -9
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +116 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cql_ruby_spec.rb +1 -1
- data/spec/cql_sql_spec.rb +3 -3
- data/spec/cql_symbol_tables_spec.rb +30 -30
- data/spec/cqldump_spec.rb +4 -4
- data/spec/helpers/array_matcher.rb +32 -27
- data/spec/helpers/diff_matcher.rb +6 -26
- data/spec/helpers/file_matcher.rb +41 -32
- data/spec/helpers/parse_to_ast_matcher.rb +76 -0
- data/spec/helpers/string_matcher.rb +32 -31
- data/spec/norma_cql_spec.rb +1 -1
- data/spec/norma_ruby_spec.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +1 -1
- data/spec/norma_sql_spec.rb +3 -1
- data/spec/norma_tables_spec.rb +1 -1
- data/spec/ruby_api_spec.rb +23 -0
- data/spec/spec_helper.rb +5 -4
- metadata +66 -66
- data/examples/CQL/OrienteeringER.cql +0 -58
- data/lib/activefacts/api.rb +0 -44
- data/lib/activefacts/api/concept.rb +0 -410
- data/lib/activefacts/api/constellation.rb +0 -128
- data/lib/activefacts/api/entity.rb +0 -256
- data/lib/activefacts/api/instance.rb +0 -60
- data/lib/activefacts/api/instance_index.rb +0 -80
- data/lib/activefacts/api/numeric.rb +0 -167
- data/lib/activefacts/api/role.rb +0 -80
- data/lib/activefacts/api/role_proxy.rb +0 -70
- data/lib/activefacts/api/role_values.rb +0 -117
- data/lib/activefacts/api/standard_types.rb +0 -87
- data/lib/activefacts/api/support.rb +0 -65
- data/lib/activefacts/api/value.rb +0 -135
- data/lib/activefacts/api/vocabulary.rb +0 -82
- data/spec/api/autocounter.rb +0 -82
- data/spec/api/constellation.rb +0 -130
- data/spec/api/entity_type.rb +0 -103
- data/spec/api/instance.rb +0 -461
- data/spec/api/roles.rb +0 -124
- data/spec/api/value_type.rb +0 -112
- data/spec/api_spec.rb +0 -13
- data/spec/cql/matching_spec.rb +0 -517
- data/spec/cql/unit_spec.rb +0 -394
- data/spec/spec.opts +0 -1
data/spec/cql_mysql_spec.rb
CHANGED
data/spec/cql_ruby_spec.rb
CHANGED
data/spec/cql_sql_spec.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
|
|
4
4
|
#
|
|
5
5
|
|
|
6
|
-
require '
|
|
6
|
+
require 'spec_helper'
|
|
7
7
|
require 'stringio'
|
|
8
8
|
require 'activefacts/vocabulary'
|
|
9
9
|
require 'activefacts/support'
|
|
@@ -58,8 +58,8 @@ describe "CQL Loader with SQL output" do
|
|
|
58
58
|
}
|
|
59
59
|
else
|
|
60
60
|
# Discard index names:
|
|
61
|
-
sql_text.gsub!(/
|
|
62
|
-
expected_text.gsub!(/
|
|
61
|
+
sql_text.gsub!(/ INDEX (\[[^\]]*\]|`[^`]*`|[^ ]*) ON /, ' INDEX <Name is hidden> ON ')
|
|
62
|
+
expected_text.gsub!(/ INDEX (\[[^\]]*\]|`[^`]*`|[^ ]*) ON /, ' INDEX <Name is hidden> ON ')
|
|
63
63
|
sql_text.should_not differ_from(expected_text)
|
|
64
64
|
File.delete(actual_file) # It succeeded, we don't need the file.
|
|
65
65
|
end
|
|
@@ -11,8 +11,8 @@ require 'activefacts/input/cql'
|
|
|
11
11
|
|
|
12
12
|
describe "CQL Symbol table" do
|
|
13
13
|
|
|
14
|
-
# A Form here is a form of reference to a
|
|
15
|
-
# Struct.new("Form", :
|
|
14
|
+
# A Form here is a form of reference to a object_type, being a name and optional adjectives, possibly designated by a role name:
|
|
15
|
+
# Struct.new("Form", :object_type, :name, :leading_adjective, :trailing_adjective, :role_name)
|
|
16
16
|
# def initialize(constellation, vocabulary)
|
|
17
17
|
# def bind(words, leading_adjective = nil, trailing_adjective = nil, role_name = nil, allowed_forward = false, leading_speculative = false, trailing_speculative = false)
|
|
18
18
|
|
|
@@ -106,7 +106,7 @@ describe "CQL Symbol table" do
|
|
|
106
106
|
|
|
107
107
|
player, bound = @symbols.bind(*args)
|
|
108
108
|
player.should_not be_nil
|
|
109
|
-
player.should == bound.
|
|
109
|
+
player.should == bound.object_type
|
|
110
110
|
[bound.name, bound.leading_adjective, bound.trailing_adjective, bound.role_name].should == result
|
|
111
111
|
else
|
|
112
112
|
lambda {player, bound = @symbols.bind(*args)}.should raise_error
|
|
@@ -115,17 +115,17 @@ describe "CQL Symbol table" do
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
it "should disallow binding to a role name where a leading adjective is provided" do
|
|
118
|
-
|
|
118
|
+
object_type, = @symbols.bind("Name", nil, nil, "GivenName", true)
|
|
119
119
|
lambda{player, bound = @symbols.bind("GivenName", "SomeAdj")}.should raise_error
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
it "should disallow binding to a role name where a trailing adjective is provided" do
|
|
123
|
-
|
|
123
|
+
object_type, = @symbols.bind("Name", nil, nil, "GivenName", true)
|
|
124
124
|
lambda{player, bound = @symbols.bind("GivenName", nil, "SomeAdj")}.should raise_error
|
|
125
125
|
end
|
|
126
126
|
|
|
127
127
|
it "should disallow binding to a role name and defining a new role name" do
|
|
128
|
-
|
|
128
|
+
object_type, = @symbols.bind("Name", nil, nil, "GivenName", true)
|
|
129
129
|
lambda{player, bound = @symbols.bind("GivenName", nil, nil, "SomeName")}.should raise_error
|
|
130
130
|
end
|
|
131
131
|
|
|
@@ -137,50 +137,50 @@ describe "CQL Symbol table" do
|
|
|
137
137
|
]
|
|
138
138
|
|
|
139
139
|
it "should allow adding a role name to an adjectival form without one" do
|
|
140
|
-
|
|
140
|
+
object_type, = @symbols.bind("Name", "Given", nil, nil, true)
|
|
141
141
|
player, bound = @symbols.bind("Name", nil, nil, "GivenName")
|
|
142
|
-
player.should ==
|
|
142
|
+
player.should == object_type
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
it "should create new binding with a role name rather than binding to existing simple player without adjectives" do
|
|
146
|
-
|
|
146
|
+
object_type, bare = @symbols.bind("Name", nil, nil, nil, true)
|
|
147
147
|
player, bound = @symbols.bind("Name", nil, nil, "SomeAdj")
|
|
148
148
|
bare.should_not == bound
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
-
it "should disallow adding a role name which is the name of an existing
|
|
152
|
-
|
|
151
|
+
it "should disallow adding a role name which is the name of an existing object_type" do
|
|
152
|
+
object_type, = @symbols.bind("Name", "Given", nil, nil, true)
|
|
153
153
|
lambda{player, bound = @symbols.bind("Name", "Given", nil, "Date")}.should raise_error
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
it "should disallow adding a role name to a role player that already has one" do
|
|
157
|
-
|
|
157
|
+
object_type, first = @symbols.bind("Name", "Given", nil, "GivenName", true)
|
|
158
158
|
player, bound = @symbols.bind("Name", "Given", nil, "FirstName")
|
|
159
159
|
first.should_not == bound
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
it "should bind to an existing player without adjectives" do
|
|
163
|
-
|
|
163
|
+
object_type, = @symbols.bind("Name", nil, nil, nil, true)
|
|
164
164
|
player, bound = @symbols.bind("Name")
|
|
165
|
-
player.should ==
|
|
165
|
+
player.should == object_type
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
it "should bind to an existing player using a leading adjective" do
|
|
169
|
-
|
|
169
|
+
object_type, = @symbols.bind("Name", nil, nil, nil, true)
|
|
170
170
|
player, bound = @symbols.bind("Name", "Given")
|
|
171
|
-
player.should ==
|
|
171
|
+
player.should == object_type
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
it "should bind to an existing player using a trailing adjective" do
|
|
175
|
-
|
|
175
|
+
object_type, = @symbols.bind("Name", nil, nil, nil, true)
|
|
176
176
|
player, bound = @symbols.bind("Name", nil, "Donné")
|
|
177
|
-
player.should ==
|
|
177
|
+
player.should == object_type
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
it "should bind to an existing player only using the defined leading adjective" do
|
|
181
|
-
|
|
181
|
+
object_type, = @symbols.bind("Name", "Given", nil, nil, true)
|
|
182
182
|
player, bound = @symbols.bind("Name", "Given")
|
|
183
|
-
player.should ==
|
|
183
|
+
player.should == object_type
|
|
184
184
|
forms = [bound]
|
|
185
185
|
|
|
186
186
|
player, alt = @symbols.bind("Name")
|
|
@@ -196,9 +196,9 @@ describe "CQL Symbol table" do
|
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
it "should bind to an existing player only using a defined trailing adjective" do
|
|
199
|
-
|
|
199
|
+
object_type, = @symbols.bind("Name", nil, "Donné", nil, true)
|
|
200
200
|
player, bound = @symbols.bind("Name", nil, "Donné")
|
|
201
|
-
player.should ==
|
|
201
|
+
player.should == object_type
|
|
202
202
|
forms = [bound]
|
|
203
203
|
|
|
204
204
|
player, alt = @symbols.bind("Name")
|
|
@@ -214,9 +214,9 @@ describe "CQL Symbol table" do
|
|
|
214
214
|
end
|
|
215
215
|
|
|
216
216
|
it "should bind to an existing player only using defined leading and trailing adjective" do
|
|
217
|
-
|
|
217
|
+
object_type, = @symbols.bind("Name", "Given", "Donné", nil, true)
|
|
218
218
|
player, bound = @symbols.bind("Name", "Given", "Donné")
|
|
219
|
-
player.should ==
|
|
219
|
+
player.should == object_type
|
|
220
220
|
forms = [bound]
|
|
221
221
|
|
|
222
222
|
player, alt = @symbols.bind("Name")
|
|
@@ -232,9 +232,9 @@ describe "CQL Symbol table" do
|
|
|
232
232
|
end
|
|
233
233
|
|
|
234
234
|
it "should bind to an existing player using a speculative leading adjective" do
|
|
235
|
-
|
|
235
|
+
object_type, = @symbols.bind("Name", "Given", nil, nil, true)
|
|
236
236
|
player, bound = @symbols.bind("Name", l = "Given", t = "Donné", nil, nil, true, true)
|
|
237
|
-
player.should ==
|
|
237
|
+
player.should == object_type
|
|
238
238
|
bound.leading_adjective.should == "Given"
|
|
239
239
|
bound.trailing_adjective.should be_nil
|
|
240
240
|
l.should be_empty
|
|
@@ -242,17 +242,17 @@ describe "CQL Symbol table" do
|
|
|
242
242
|
end
|
|
243
243
|
|
|
244
244
|
it "should bind to an existing player using a speculative trailing adjective" do
|
|
245
|
-
|
|
245
|
+
object_type, = @symbols.bind("Name", nil, "Donné", nil, true)
|
|
246
246
|
player, bound = @symbols.bind("Name", l = "Given", t = "Donné", nil, nil, true, true)
|
|
247
|
-
player.should ==
|
|
247
|
+
player.should == object_type
|
|
248
248
|
l.should == "Given"
|
|
249
249
|
t.should be_empty
|
|
250
250
|
end
|
|
251
251
|
|
|
252
252
|
it "should bind to an existing player using a speculative leading and trailing adjective" do
|
|
253
|
-
|
|
253
|
+
object_type, = @symbols.bind("Name", "Given", "Donné", nil, true)
|
|
254
254
|
player, bound = @symbols.bind("Name", l = "Given", t = "Donné", nil, nil, true, true)
|
|
255
|
-
player.should ==
|
|
255
|
+
player.should == object_type
|
|
256
256
|
l.should be_empty
|
|
257
257
|
t.should be_empty
|
|
258
258
|
end
|
data/spec/cqldump_spec.rb
CHANGED
|
@@ -68,8 +68,8 @@ END
|
|
|
68
68
|
def one_to_many(one, many, reading)
|
|
69
69
|
# Join them with a fact type:
|
|
70
70
|
ft = @constellation.FactType(:new)
|
|
71
|
-
role0 = @constellation.Role(ft, 0, :
|
|
72
|
-
role1 = @constellation.Role(ft, 1, :
|
|
71
|
+
role0 = @constellation.Role(ft, 0, :object_type => one)
|
|
72
|
+
role1 = @constellation.Role(ft, 1, :object_type => many)
|
|
73
73
|
|
|
74
74
|
# Make a role sequence:
|
|
75
75
|
rs = @constellation.RoleSequence(:new)
|
|
@@ -90,8 +90,8 @@ END
|
|
|
90
90
|
def one_to_one(first, second, reading)
|
|
91
91
|
# Join them with a fact type:
|
|
92
92
|
ft = @constellation.FactType(:new)
|
|
93
|
-
role0 = @constellation.Role(ft, 0, :
|
|
94
|
-
role1 = @constellation.Role(ft, 1, :
|
|
93
|
+
role0 = @constellation.Role(ft, 0, :object_type => first)
|
|
94
|
+
role1 = @constellation.Role(ft, 1, :object_type => second)
|
|
95
95
|
|
|
96
96
|
# Make a role sequence for the reading
|
|
97
97
|
rs = @constellation.RoleSequence(:new)
|
|
@@ -1,35 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
module RSpec
|
|
2
|
+
module Matchers
|
|
3
|
+
class ArrayMatcher < Matcher
|
|
4
|
+
def initialize expected
|
|
5
|
+
super(:be_different_array_from, expected) do |*_expected|
|
|
6
|
+
match_for_should do |actual|
|
|
7
|
+
perform_match(actual, _expected[0])
|
|
8
|
+
@extra + @missing != []
|
|
9
|
+
end
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
11
|
+
match_for_should_not do |actual|
|
|
12
|
+
perform_match(actual, _expected[0])
|
|
13
|
+
@extra + @missing == []
|
|
14
|
+
end
|
|
8
15
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
16
|
+
def perform_match(actual, expected)
|
|
17
|
+
@extra = actual - expected
|
|
18
|
+
@missing = expected - actual
|
|
19
|
+
end
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
def failure_message_for_should
|
|
22
|
+
"expected a difference in the two lists, but got none"
|
|
23
|
+
end
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
failure_message_for_should_not do |actual|
|
|
26
|
+
"expected no difference, but result #{
|
|
27
|
+
[ (@missing.empty? ? nil : 'lacks '+@missing.sort.inspect),
|
|
28
|
+
(@extra.empty? ? nil : 'has extra '+@extra.sort.inspect)
|
|
29
|
+
].compact * ' and '
|
|
30
|
+
}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
25
34
|
end
|
|
26
|
-
end
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
def be_different_array_from(expected)
|
|
37
|
+
ArrayMatcher.new(expected)
|
|
38
|
+
end
|
|
30
39
|
end
|
|
31
40
|
end
|
|
32
|
-
|
|
33
|
-
Spec::Runner.configure do |config|
|
|
34
|
-
config.include(ArrayMatcher)
|
|
35
|
-
end
|
|
@@ -1,38 +1,18 @@
|
|
|
1
1
|
require 'pathname'
|
|
2
2
|
|
|
3
|
-
module
|
|
4
|
-
|
|
5
|
-
def
|
|
3
|
+
module RSpec
|
|
4
|
+
module Matchers
|
|
5
|
+
def differ_from(expected)
|
|
6
6
|
case expected
|
|
7
7
|
when Pathname
|
|
8
|
-
|
|
8
|
+
FileMatcher.new(expected)
|
|
9
9
|
when Array
|
|
10
|
-
|
|
10
|
+
ArrayMatcher.new(expected)
|
|
11
11
|
when String
|
|
12
|
-
|
|
12
|
+
FileMatcher.new(expected)
|
|
13
13
|
else
|
|
14
14
|
raise "DiffMatcher doesn't know how to match a #{expected.class}"
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
|
-
|
|
18
|
-
def matches?(actual)
|
|
19
|
-
@matcher.matches?(actual)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def failure_message
|
|
23
|
-
@matcher.failure_message
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def negative_failure_message
|
|
27
|
-
@matcher.negative_failure_message
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def differ_from(expected)
|
|
32
|
-
DifferFrom.new(expected)
|
|
33
17
|
end
|
|
34
18
|
end
|
|
35
|
-
|
|
36
|
-
Spec::Runner.configure do |config|
|
|
37
|
-
config.include(DiffMatcher)
|
|
38
|
-
end
|
|
@@ -1,41 +1,50 @@
|
|
|
1
1
|
require 'diff/lcs'
|
|
2
2
|
|
|
3
|
-
module
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
module RSpec
|
|
4
|
+
module Matchers
|
|
5
|
+
class FileMatcher < Matcher
|
|
6
|
+
def initialize expected
|
|
7
|
+
super(:have_different_contents, expected) do |*_expected|
|
|
8
|
+
match_for_should do |actual|
|
|
9
|
+
perform_match(actual, _expected[0])
|
|
10
|
+
end
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
differences = Diff::LCS::diff(@expected, actual_lines)
|
|
14
|
-
@diff = differences.map do |chunk|
|
|
15
|
-
added_at = (add = chunk.detect{|d| d.action == '+'}) && add.position+1
|
|
16
|
-
removed_at = (remove = chunk.detect{|d| d.action == '-'}) && remove.position+1
|
|
17
|
-
"Line #{added_at}/#{removed_at}:\n"+
|
|
18
|
-
chunk.map do |change|
|
|
19
|
-
"#{change.action} #{change.element}"
|
|
20
|
-
end*"\n"
|
|
21
|
-
end*"\n"
|
|
22
|
-
@diff != ''
|
|
23
|
-
end
|
|
12
|
+
match_for_should_not do |actual|
|
|
13
|
+
!perform_match(actual, _expected[0])
|
|
14
|
+
end
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
def perform_match(actual, expected)
|
|
17
|
+
expected = File.open(expected).read if expected.is_a?(Pathname)
|
|
18
|
+
expected = expected.scan(/[^\n]+/) unless expected.is_a?(Array)
|
|
19
|
+
|
|
20
|
+
actual = File.open(actual).read if actual.is_a?(Pathname)
|
|
21
|
+
actual = actual.scan(/[^\n]+/) unless actual.is_a?(Array)
|
|
22
|
+
|
|
23
|
+
differences = Diff::LCS::diff(expected, actual)
|
|
24
|
+
@diff = differences.map do |chunk|
|
|
25
|
+
added_at = (add = chunk.detect{|d| d.action == '+'}) && add.position+1
|
|
26
|
+
removed_at = (remove = chunk.detect{|d| d.action == '-'}) && remove.position+1
|
|
27
|
+
"Line #{added_at}/#{removed_at}:\n"+
|
|
28
|
+
chunk.map do |change|
|
|
29
|
+
"#{change.action} #{change.element}"
|
|
30
|
+
end*"\n"
|
|
31
|
+
end*"\n"
|
|
32
|
+
@diff != ''
|
|
33
|
+
end
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
def failure_message_for_should
|
|
36
|
+
"expected a difference, but got none"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
failure_message_for_should_not do |actual|
|
|
40
|
+
"expected no difference, but got:\n#{@diff}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
31
44
|
end
|
|
32
|
-
end
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
def have_different_contents(expected)
|
|
47
|
+
FileMatcher.new(expected)
|
|
48
|
+
end
|
|
36
49
|
end
|
|
37
50
|
end
|
|
38
|
-
|
|
39
|
-
Spec::Runner.configure do |config|
|
|
40
|
-
config.include(FileMatcher)
|
|
41
|
-
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'rspec/expectations'
|
|
2
|
+
|
|
3
|
+
require 'activefacts/cql'
|
|
4
|
+
require 'activefacts/support'
|
|
5
|
+
require 'activefacts/api/support'
|
|
6
|
+
require 'helpers/test_parser'
|
|
7
|
+
|
|
8
|
+
RSpec::Matchers.define :parse_to_ast do |*expected_asts|
|
|
9
|
+
def canonicalise(s)
|
|
10
|
+
if s.is_a?(Array)
|
|
11
|
+
s.map{|e| canonicalise(e)}
|
|
12
|
+
else
|
|
13
|
+
s.to_s.gsub(/\s+/,' ').strip
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
match do |actual|
|
|
18
|
+
@parser = TestParser.new
|
|
19
|
+
@result = @parser.parse_all(actual, :definition)
|
|
20
|
+
|
|
21
|
+
# If the expected_asts is "false", treat this test as pending:
|
|
22
|
+
if expected_asts == [false]
|
|
23
|
+
if @result
|
|
24
|
+
# Unfortunately there's no way to say why the failure was expected here
|
|
25
|
+
# RSpec stores it in example.metadata[:execution_result][:pending_message]
|
|
26
|
+
raise RSpec::Core::PendingExampleFixedError.new
|
|
27
|
+
else
|
|
28
|
+
throw :pending_declared_in_example, "Should parse #{actual.strip.inspect}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# If we failed to parse, fail and say why:
|
|
33
|
+
next false unless @result
|
|
34
|
+
|
|
35
|
+
# Otherwise compare the canonical form of the AST
|
|
36
|
+
@canonical_form = @result.map{|d| canonicalise(d.ast)}
|
|
37
|
+
|
|
38
|
+
# If we weren't given an AST, this test is pending. Show what result we obtained:
|
|
39
|
+
throw :pending_declared_in_example, actual.inspect+' should parse to ['+@canonical_form*', '+']' if expected_asts.empty?
|
|
40
|
+
|
|
41
|
+
@canonical_form == canonicalise(expected_asts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
failure_message_for_should do
|
|
45
|
+
if !@result
|
|
46
|
+
@parser.failure_reason
|
|
47
|
+
else
|
|
48
|
+
"Expected %q{#{canonicalise(expected_asts)}}\nbut got: %q{#{@canonical_form}}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
RSpec::Matchers.define :fail_to_parse do |*error_regexp|
|
|
54
|
+
match do |actual|
|
|
55
|
+
@parser = TestParser.new
|
|
56
|
+
@actual = actual
|
|
57
|
+
@result = @parser.parse_all(actual, :definition)
|
|
58
|
+
@result.should be_nil
|
|
59
|
+
if @re = error_regexp[0]
|
|
60
|
+
@parser.failure_reason.should =~ @re
|
|
61
|
+
else
|
|
62
|
+
throw :pending_declared_in_example, actual.inspect+' fails, please add message pattern to match '+@parser.failure_reason.inspect
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
failure_message_for_should do
|
|
67
|
+
if @result
|
|
68
|
+
@canonical_form = @result.map{|d| canonicalise(d.ast)}
|
|
69
|
+
"Expected not to succeed in parsing #{actual.inspect}\nbut got #{@canonical_form.inspect}"
|
|
70
|
+
else
|
|
71
|
+
"Failed as expected in parsing #{actual.inspect}\n" +
|
|
72
|
+
"but not for the right reason: #{@re.inspect}\n"+
|
|
73
|
+
"got #{@parser.failure_reason.inspect}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|