solve 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +5 -0
- data/README.md +8 -7
- data/lib/solve.rb +10 -29
- data/lib/solve/artifact.rb +91 -52
- data/lib/solve/constraint.rb +109 -24
- data/lib/solve/demand.rb +26 -17
- data/lib/solve/dependency.rb +15 -1
- data/lib/solve/errors.rb +23 -20
- data/lib/solve/gem_version.rb +1 -1
- data/lib/solve/graph.rb +76 -84
- data/lib/solve/solver.rb +246 -0
- data/lib/solve/solver/constraint_row.rb +17 -0
- data/lib/solve/solver/constraint_table.rb +27 -0
- data/lib/solve/solver/variable.rb +41 -0
- data/lib/solve/solver/variable_table.rb +50 -0
- data/lib/solve/version.rb +53 -16
- data/solve.gemspec +2 -3
- data/spec/acceptance/solutions_spec.rb +81 -8
- data/spec/unit/solve/artifact_spec.rb +73 -49
- data/spec/unit/solve/constraint_spec.rb +36 -30
- data/spec/unit/solve/demand_spec.rb +22 -13
- data/spec/unit/solve/dependency_spec.rb +15 -0
- data/spec/unit/solve/graph_spec.rb +98 -142
- data/spec/unit/solve/solver_spec.rb +302 -0
- data/spec/unit/solve/version_spec.rb +110 -0
- metadata +42 -96
- data/lib/solve/core_ext.rb +0 -3
- data/lib/solve/core_ext/kernel.rb +0 -33
@@ -7,33 +7,7 @@ describe Solve::Constraint do
|
|
7
7
|
describe "ClassMethods" do
|
8
8
|
subject { Solve::Constraint }
|
9
9
|
|
10
|
-
describe "
|
11
|
-
it "returns an array containing two items" do
|
12
|
-
subject.parse(valid_string).should have(2).items
|
13
|
-
end
|
14
|
-
|
15
|
-
it "returns the operator at index 0" do
|
16
|
-
subject.parse(valid_string)[0].should eql(">=")
|
17
|
-
end
|
18
|
-
|
19
|
-
it "returns the version string at index 1" do
|
20
|
-
subject.parse(valid_string)[1].should eql("0.0.0")
|
21
|
-
end
|
22
|
-
|
23
|
-
context "given a string that does not match the Constraint REGEXP" do
|
24
|
-
it "returns nil" do
|
25
|
-
subject.parse(invalid_string).should be_nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "given a string that does not contain an operator" do
|
30
|
-
it "returns a constraint constraint with a default operator (=)" do
|
31
|
-
subject.parse("1.0.0")[0].should eql("=")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe "#initialize" do
|
10
|
+
describe "::new" do
|
37
11
|
it "returns a new instance of Constraint" do
|
38
12
|
subject.new(valid_string).should be_a(Solve::Constraint)
|
39
13
|
end
|
@@ -53,7 +27,7 @@ describe Solve::Constraint do
|
|
53
27
|
it "raises an InvalidConstraintFormat error" do
|
54
28
|
lambda {
|
55
29
|
subject.new(invalid_string)
|
56
|
-
}.should raise_error(Solve::InvalidConstraintFormat)
|
30
|
+
}.should raise_error(Solve::Errors::InvalidConstraintFormat)
|
57
31
|
end
|
58
32
|
end
|
59
33
|
|
@@ -61,7 +35,39 @@ describe Solve::Constraint do
|
|
61
35
|
it "raises an InvalidConstraintFormat error" do
|
62
36
|
lambda {
|
63
37
|
subject.new(nil)
|
64
|
-
}.should raise_error(Solve::InvalidConstraintFormat)
|
38
|
+
}.should raise_error(Solve::Errors::InvalidConstraintFormat)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "given a string containing only a major and minor version" do
|
43
|
+
it "has a nil value for patch" do
|
44
|
+
subject.new("~> 1.2").patch.should be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "::split" do
|
50
|
+
it "returns an array containing two items" do
|
51
|
+
subject.split(valid_string).should have(2).items
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns the operator at index 0" do
|
55
|
+
subject.split(valid_string)[0].should eql(">=")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns the version string at index 1" do
|
59
|
+
subject.split(valid_string)[1].should eql("0.0.0")
|
60
|
+
end
|
61
|
+
|
62
|
+
context "given a string that does not match the Constraint REGEXP" do
|
63
|
+
it "returns nil" do
|
64
|
+
subject.split(invalid_string).should be_nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "given a string that does not contain an operator" do
|
69
|
+
it "returns a constraint constraint with a default operator (=)" do
|
70
|
+
subject.split("1.0.0")[0].should eql("=")
|
65
71
|
end
|
66
72
|
end
|
67
73
|
end
|
@@ -146,7 +152,7 @@ describe Solve::Constraint do
|
|
146
152
|
end
|
147
153
|
end
|
148
154
|
|
149
|
-
context "
|
155
|
+
context "aproximately (~>)" do
|
150
156
|
subject { Solve::Constraint.new("~> 1.0.0") }
|
151
157
|
|
152
158
|
it "returns true if the given version is equal to the version constraint" do
|
@@ -1,52 +1,61 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Solve::Demand do
|
4
|
-
let(:
|
4
|
+
let(:solver) { double('solver') }
|
5
5
|
let(:name) { "league" }
|
6
6
|
|
7
7
|
describe "ClassMethods" do
|
8
8
|
subject { Solve::Demand }
|
9
9
|
|
10
|
-
describe "::
|
10
|
+
describe "::new" do
|
11
11
|
it "accepts a string for the constraint parameter" do
|
12
|
-
subject.new(
|
12
|
+
subject.new(solver, name, "= 0.0.1").constraint.to_s.should eql("= 0.0.1")
|
13
13
|
end
|
14
14
|
|
15
15
|
it "accepts a Solve::Constraint for the constraint parameter" do
|
16
16
|
constraint = Solve::Constraint.new("= 0.0.1")
|
17
17
|
|
18
|
-
subject.new(
|
18
|
+
subject.new(solver, name, constraint).constraint.should eql(constraint)
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when no value for 'constraint' is given" do
|
22
|
+
it "uses a default of >= 0.0.0" do
|
23
|
+
demand = subject.new(solver, name)
|
24
|
+
|
25
|
+
demand.constraint.operator.should eql(">=")
|
26
|
+
demand.constraint.version.to_s.should eql("0.0.0")
|
27
|
+
end
|
19
28
|
end
|
20
29
|
end
|
21
30
|
end
|
22
31
|
|
23
32
|
let(:constraint) { "~> 1.0.0" }
|
24
|
-
subject { Solve::Demand.new(
|
33
|
+
subject { Solve::Demand.new(solver, name, constraint) }
|
25
34
|
|
26
35
|
describe "#delete" do
|
27
|
-
context "given the
|
28
|
-
subject { Solve::Demand.new(
|
36
|
+
context "given the demand is related to a solver" do
|
37
|
+
subject { Solve::Demand.new(solver, name, constraint) }
|
29
38
|
|
30
39
|
before(:each) do
|
31
|
-
|
40
|
+
solver.should_receive(:remove_demand).with(subject).and_return(subject)
|
32
41
|
end
|
33
42
|
|
34
|
-
it "notifies the
|
43
|
+
it "notifies the solver that the demand should be removed" do
|
35
44
|
subject.delete
|
36
45
|
end
|
37
46
|
|
38
|
-
it "sets the
|
47
|
+
it "sets the solver attribute to nil" do
|
39
48
|
subject.delete
|
40
49
|
|
41
|
-
subject.
|
50
|
+
subject.solver.should be_nil
|
42
51
|
end
|
43
52
|
|
44
|
-
it "returns the instance of
|
53
|
+
it "returns the instance of demand deleted from the solver" do
|
45
54
|
subject.delete.should eql(subject)
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|
49
|
-
context "given the
|
58
|
+
context "given the demand is not the member of a solver" do
|
50
59
|
subject { Solve::Demand.new(nil, name, constraint) }
|
51
60
|
|
52
61
|
it "returns nil" do
|
@@ -1,6 +1,21 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Solve::Dependency do
|
4
|
+
describe "ClassMethods" do
|
5
|
+
subject { Solve::Dependency }
|
6
|
+
|
7
|
+
describe "::new" do
|
8
|
+
context "when no value for 'constraint' is given" do
|
9
|
+
it "uses a default of >= 0.0.0" do
|
10
|
+
dep = subject.new(double('artifact'), "ntp")
|
11
|
+
|
12
|
+
dep.constraint.operator.should eql(">=")
|
13
|
+
dep.constraint.version.to_s.should eql("0.0.0")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
4
19
|
let(:artifact) { double('artifact') }
|
5
20
|
let(:name) { 'nginx' }
|
6
21
|
let(:constraint) { "~> 0.0.1" }
|
@@ -1,6 +1,52 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Solve::Graph do
|
4
|
+
describe "ClassMethods" do
|
5
|
+
subject { Solve::Graph }
|
6
|
+
|
7
|
+
describe "::key_for" do
|
8
|
+
context "given a Solve::Artifact" do
|
9
|
+
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.2.3") }
|
10
|
+
|
11
|
+
it "delegates to ::artifact_key with the name and version of the artifact" do
|
12
|
+
subject.should_receive(:artifact_key).with(artifact.name, artifact.version)
|
13
|
+
|
14
|
+
subject.key_for(artifact)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "given a Solve::Dependency" do
|
19
|
+
let(:demand) { Solve::Dependency.new(double('artifact'), "ntp", "= 2.3.4") }
|
20
|
+
|
21
|
+
it "delegates to ::dependency_key with the name and constraint of the dependency" do
|
22
|
+
subject.should_receive(:dependency_key).with(demand.name, anything)
|
23
|
+
|
24
|
+
subject.key_for(demand)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "given an unknown object" do
|
29
|
+
it "raises an ArgumentError" do
|
30
|
+
lambda {
|
31
|
+
subject.key_for("hello")
|
32
|
+
}.should raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "::artifact_key" do
|
38
|
+
it "returns a symbol containing the name and version of the artifact" do
|
39
|
+
subject.artifact_key("nginx", "1.2.3").should eql(:'nginx-1.2.3')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "::dependency_key" do
|
44
|
+
it "returns a symbol containing the name and constraint of the dependency" do
|
45
|
+
subject.dependency_key("ntp", "= 2.3.4").should eql(:'ntp-= 2.3.4')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
4
50
|
subject { Solve::Graph.new }
|
5
51
|
|
6
52
|
describe "#artifacts" do
|
@@ -78,196 +124,106 @@ describe Solve::Graph do
|
|
78
124
|
end
|
79
125
|
end
|
80
126
|
|
81
|
-
describe "#
|
82
|
-
|
83
|
-
|
84
|
-
it "adds a Solve::Artifact to the collection of artifacts" do
|
85
|
-
subject.add_artifact(artifact)
|
86
|
-
|
87
|
-
subject.should have_artifact(artifact)
|
88
|
-
subject.artifacts.should have(1).item
|
127
|
+
describe "#get_artifact" do
|
128
|
+
before(:each) do
|
129
|
+
subject.artifacts("nginx", "1.0.0")
|
89
130
|
end
|
90
131
|
|
91
|
-
it "
|
92
|
-
subject.
|
93
|
-
subject.add_artifact(artifact)
|
132
|
+
it "returns an instance of artifact of the matching name and version" do
|
133
|
+
artifact = subject.get_artifact("nginx", "1.0.0")
|
94
134
|
|
95
|
-
|
135
|
+
artifact.should be_a(Solve::Artifact)
|
136
|
+
artifact.name.should eql("nginx")
|
137
|
+
artifact.version.to_s.should eql("1.0.0")
|
96
138
|
end
|
97
|
-
end
|
98
|
-
|
99
|
-
describe "#remove_artifact" do
|
100
|
-
let(:artifact) { double('artifact', name: "nginx", version: "1.0.0") }
|
101
|
-
|
102
|
-
context "given the artifact is a member of the collection" do
|
103
|
-
before(:each) { subject.add_artifact(artifact) }
|
104
139
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
subject.artifacts.should have(0).items
|
140
|
+
context "when an artifact of the given name is not in the collection of artifacts" do
|
141
|
+
it "returns nil" do
|
142
|
+
subject.get_artifact("nothere", "1.0.0").should be_nil
|
109
143
|
end
|
110
|
-
|
111
|
-
it "returns the removed Solve::Artifact" do
|
112
|
-
subject.remove_artifact(artifact).should eql(artifact)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
context "given the artifact is not a member of the collection" do
|
117
|
-
it "should return nil" do
|
118
|
-
subject.remove_artifact(artifact).should be_nil
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "#has_artifact?" do
|
124
|
-
let(:artifact) { double('artifact', name: "nginx", version: "1.0.0") }
|
125
|
-
|
126
|
-
it "returns true if the given Solve::Artifact is a member of the collection" do
|
127
|
-
subject.add_artifact(artifact)
|
128
|
-
|
129
|
-
subject.has_artifact?(artifact).should be_true
|
130
|
-
end
|
131
|
-
|
132
|
-
it "returns false if the given Solve::Artifact is not a member of the collection" do
|
133
|
-
subject.has_artifact?(artifact).should be_false
|
134
144
|
end
|
135
145
|
end
|
136
146
|
|
137
|
-
describe "#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
it "the artifact has the given name" do
|
148
|
-
subject.demands(name, constraint).name.should eql(name)
|
149
|
-
end
|
150
|
-
|
151
|
-
it "the artifact has the given constraint" do
|
152
|
-
subject.demands(name, constraint).constraint.to_s.should eql(constraint)
|
153
|
-
end
|
154
|
-
|
155
|
-
it "adds an artifact to the demands collection" do
|
156
|
-
subject.demands(name, constraint)
|
157
|
-
|
158
|
-
subject.demands.should have(1).item
|
159
|
-
end
|
160
|
-
|
161
|
-
it "the artifact added matches the given name" do
|
162
|
-
subject.demands(name, constraint)
|
163
|
-
|
164
|
-
subject.demands[0].name.should eql(name)
|
165
|
-
end
|
166
|
-
|
167
|
-
it "the artifact added matches the given constraint" do
|
168
|
-
subject.demands(name, constraint)
|
169
|
-
|
170
|
-
subject.demands[0].constraint.to_s.should eql(constraint)
|
171
|
-
end
|
172
|
-
end
|
147
|
+
describe "#versions" do
|
148
|
+
let(:artifacts) do
|
149
|
+
[
|
150
|
+
double('artifact', name: 'nginx', version: Solve::Version.new('1.0.0')),
|
151
|
+
double('artifact', name: 'nginx', version: Solve::Version.new('2.0.0')),
|
152
|
+
double('artifact', name: 'nginx', version: Solve::Version.new('3.0.0')),
|
153
|
+
double('artifact', name: 'nginx', version: Solve::Version.new('4.0.0')),
|
154
|
+
double('artifact', name: 'nginx', version: Solve::Version.new('5.0.0')),
|
155
|
+
double('artifact', name: 'mysql', version: Solve::Version.new('4.0.0'))
|
156
|
+
]
|
173
157
|
end
|
174
158
|
|
175
|
-
|
176
|
-
|
177
|
-
subject.demands("nginx").constraint.to_s.should eql(">= 0.0.0")
|
178
|
-
end
|
159
|
+
before(:each) do
|
160
|
+
subject.stub(:artifacts).and_return(artifacts)
|
179
161
|
end
|
180
162
|
|
181
|
-
|
182
|
-
|
183
|
-
subject.demands.should be_a(Array)
|
184
|
-
end
|
185
|
-
|
186
|
-
it "returns an empty array if no demands have been accessed" do
|
187
|
-
subject.demands.should have(0).items
|
188
|
-
end
|
189
|
-
|
190
|
-
it "returns an array containing a demand if one was accessed" do
|
191
|
-
subject.demands("nginx", "~> 0.101.5")
|
192
|
-
|
193
|
-
subject.demands.should have(1).item
|
194
|
-
end
|
163
|
+
it "returns all the artifacts matching the given name" do
|
164
|
+
subject.versions("nginx").should have(5).items
|
195
165
|
end
|
196
166
|
|
197
|
-
context "given an
|
198
|
-
it "
|
199
|
-
|
200
|
-
subject.demands(1, 2, 3)
|
201
|
-
}.should raise_error(ArgumentError, "Unexpected number of arguments. You gave: 3. Expected: 2 or less.")
|
202
|
-
end
|
203
|
-
|
204
|
-
it "raises an ArgumentError if a name argument of nil is provided" do
|
205
|
-
lambda {
|
206
|
-
subject.demands(nil)
|
207
|
-
}.should raise_error(ArgumentError, "A name must be specified. You gave: [nil].")
|
208
|
-
end
|
209
|
-
|
210
|
-
it "raises an ArgumentError if a name and constraint argument are provided but name is nil" do
|
211
|
-
lambda {
|
212
|
-
subject.demands(nil, "= 1.0.0")
|
213
|
-
}.should raise_error(ArgumentError, 'A name must be specified. You gave: [nil, "= 1.0.0"].')
|
167
|
+
context "given an optional constraint value" do
|
168
|
+
it "returns only the artifacts matching the given constraint value and name" do
|
169
|
+
subject.versions("nginx", ">= 4.0.0").should have(2).items
|
214
170
|
end
|
215
171
|
end
|
216
172
|
end
|
217
173
|
|
218
|
-
describe "#
|
219
|
-
let(:
|
174
|
+
describe "#add_artifact" do
|
175
|
+
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.0.0") }
|
220
176
|
|
221
177
|
it "adds a Solve::Artifact to the collection of artifacts" do
|
222
|
-
subject.
|
178
|
+
subject.add_artifact(artifact)
|
223
179
|
|
224
|
-
subject.should
|
225
|
-
subject.
|
180
|
+
subject.should have_artifact(artifact.name, artifact.version)
|
181
|
+
subject.artifacts.should have(1).item
|
226
182
|
end
|
227
183
|
|
228
|
-
it "should not add the same
|
229
|
-
subject.
|
230
|
-
subject.
|
184
|
+
it "should not add the same artifact twice to the collection" do
|
185
|
+
subject.add_artifact(artifact)
|
186
|
+
subject.add_artifact(artifact)
|
231
187
|
|
232
|
-
subject.
|
188
|
+
subject.artifacts.should have(1).item
|
233
189
|
end
|
234
190
|
end
|
235
191
|
|
236
|
-
describe "#
|
237
|
-
let(:
|
192
|
+
describe "#remove_artifact" do
|
193
|
+
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.0.0") }
|
238
194
|
|
239
|
-
context "given the
|
240
|
-
before(:each) { subject.
|
195
|
+
context "given the artifact is a member of the collection" do
|
196
|
+
before(:each) { subject.add_artifact(artifact) }
|
241
197
|
|
242
|
-
it "removes the Solve::Artifact from the collection of
|
243
|
-
subject.
|
198
|
+
it "removes the Solve::Artifact from the collection of artifacts" do
|
199
|
+
subject.remove_artifact(artifact)
|
244
200
|
|
245
|
-
subject.
|
201
|
+
subject.artifacts.should have(0).items
|
246
202
|
end
|
247
203
|
|
248
204
|
it "returns the removed Solve::Artifact" do
|
249
|
-
subject.
|
205
|
+
subject.remove_artifact(artifact).should eql(artifact)
|
250
206
|
end
|
251
207
|
end
|
252
208
|
|
253
|
-
context "given the
|
209
|
+
context "given the artifact is not a member of the collection" do
|
254
210
|
it "should return nil" do
|
255
|
-
subject.
|
211
|
+
subject.remove_artifact(artifact).should be_nil
|
256
212
|
end
|
257
213
|
end
|
258
214
|
end
|
259
215
|
|
260
|
-
describe "#
|
261
|
-
let(:
|
216
|
+
describe "#has_artifact?" do
|
217
|
+
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.0.0") }
|
262
218
|
|
263
219
|
it "returns true if the given Solve::Artifact is a member of the collection" do
|
264
|
-
subject.
|
220
|
+
subject.add_artifact(artifact)
|
265
221
|
|
266
|
-
subject.
|
222
|
+
subject.has_artifact?(artifact.name, artifact.version).should be_true
|
267
223
|
end
|
268
224
|
|
269
225
|
it "returns false if the given Solve::Artifact is not a member of the collection" do
|
270
|
-
subject.
|
226
|
+
subject.has_artifact?(artifact.name, artifact.version).should be_false
|
271
227
|
end
|
272
228
|
end
|
273
229
|
end
|