solve 0.2.1 → 0.3.0
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/.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
|