solve 0.8.2 → 1.0.0.rc1
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +4 -0
- data/README.md +8 -11
- data/lib/solve.rb +3 -8
- data/lib/solve/artifact.rb +44 -80
- data/lib/solve/constraint.rb +62 -46
- data/lib/solve/demand.rb +6 -21
- data/lib/solve/dependency.rb +10 -22
- data/lib/solve/errors.rb +43 -17
- data/lib/solve/gem_version.rb +1 -1
- data/lib/solve/graph.rb +43 -123
- data/lib/solve/solver.rb +134 -262
- data/lib/solve/solver/serializer.rb +1 -1
- data/solve.gemspec +3 -1
- data/spec/acceptance/benchmark.rb +45 -0
- data/spec/acceptance/large_graph_no_solution.rb +18730 -0
- data/spec/acceptance/opscode_ci_graph.rb +18600 -0
- data/spec/acceptance/solutions_spec.rb +117 -76
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/solve/artifact_spec.rb +49 -64
- data/spec/unit/solve/demand_spec.rb +19 -56
- data/spec/unit/solve/dependency_spec.rb +7 -46
- data/spec/unit/solve/graph_spec.rb +72 -209
- data/spec/unit/solve/solver/serializer_spec.rb +3 -4
- data/spec/unit/solve/solver_spec.rb +103 -247
- metadata +43 -22
- data/.ruby-version +0 -1
- data/lib/solve/solver/constraint_row.rb +0 -25
- data/lib/solve/solver/constraint_table.rb +0 -31
- data/lib/solve/solver/variable_row.rb +0 -43
- data/lib/solve/solver/variable_table.rb +0 -55
- data/lib/solve/tracers.rb +0 -50
- data/lib/solve/tracers/human_readable.rb +0 -67
- data/lib/solve/tracers/silent.rb +0 -17
- data/lib/solve/version.rb +0 -140
- data/spec/unit/solve/constraint_spec.rb +0 -708
- data/spec/unit/solve/version_spec.rb +0 -355
@@ -4,27 +4,25 @@ describe Solve::Demand do
|
|
4
4
|
let(:solver) { double('solver') }
|
5
5
|
let(:name) { "league" }
|
6
6
|
|
7
|
-
describe "
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
subject.new(solver, name, "= 0.0.1").constraint.to_s.should eql("= 0.0.1")
|
13
|
-
end
|
7
|
+
describe "#initialize" do
|
8
|
+
it "accepts a string for the constraint parameter" do
|
9
|
+
demand = Solve::Demand.new(solver, name, "= 0.0.1")
|
10
|
+
expect(demand.constraint.to_s).to eq("= 0.0.1")
|
11
|
+
end
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
it "accepts a Semverse::Constraint for the constraint parameter" do
|
14
|
+
constraint = Semverse::Constraint.new("= 0.0.1")
|
15
|
+
demand = Solve::Demand.new(solver, name, constraint)
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
expect(demand.constraint).to eq(constraint)
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
context "when no value for 'constraint' is given" do
|
21
|
+
it "uses a default of >= 0.0.0" do
|
22
|
+
demand = Solve::Demand.new(solver, name)
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
24
|
+
expect(demand.constraint.operator).to eq(">=")
|
25
|
+
expect(demand.constraint.version.to_s).to eq("0.0.0")
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
@@ -32,59 +30,24 @@ describe Solve::Demand do
|
|
32
30
|
let(:constraint) { "~> 1.0.0" }
|
33
31
|
subject { Solve::Demand.new(solver, name, constraint) }
|
34
32
|
|
35
|
-
describe "#delete" do
|
36
|
-
context "given the demand is related to a solver" do
|
37
|
-
subject { Solve::Demand.new(solver, name, constraint) }
|
38
|
-
|
39
|
-
before(:each) do
|
40
|
-
solver.should_receive(:remove_demand).with(subject).and_return(subject)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "notifies the solver that the demand should be removed" do
|
44
|
-
subject.delete
|
45
|
-
end
|
46
|
-
|
47
|
-
it "sets the solver attribute to nil" do
|
48
|
-
subject.delete
|
49
|
-
|
50
|
-
subject.solver.should be_nil
|
51
|
-
end
|
52
|
-
|
53
|
-
it "returns the instance of demand deleted from the solver" do
|
54
|
-
subject.delete.should eql(subject)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
context "given the demand is not the member of a solver" do
|
59
|
-
subject { Solve::Demand.new(nil, name, constraint) }
|
60
|
-
|
61
|
-
it "returns nil" do
|
62
|
-
subject.delete.should be_nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
33
|
describe "equality" do
|
68
34
|
it "returns true when other is a Solve::Demand with the same name and constriant" do
|
69
35
|
other = Solve::Demand.new(solver, name, constraint)
|
70
|
-
|
71
|
-
subject.should eql(other)
|
36
|
+
expect(subject).to eq(other)
|
72
37
|
end
|
73
38
|
|
74
39
|
it "returns false when other isn't a Solve::Demand" do
|
75
|
-
subject.
|
40
|
+
expect(subject).to_not eq("chicken")
|
76
41
|
end
|
77
42
|
|
78
43
|
it "returns false when other is a Solve::Demand with the same name but a different constraint" do
|
79
44
|
other = Solve::Demand.new(solver, name, "< 3.4.5")
|
80
|
-
|
81
|
-
subject.should_not eql(other)
|
45
|
+
expect(subject).to_not eq(other)
|
82
46
|
end
|
83
47
|
|
84
48
|
it "returns false when other is a Solve::Demand with the same constraint but a different name" do
|
85
49
|
other = Solve::Demand.new(solver, "chicken", constraint)
|
86
|
-
|
87
|
-
subject.should_not eql(other)
|
50
|
+
expect(subject).to_not eq(other)
|
88
51
|
end
|
89
52
|
end
|
90
53
|
end
|
@@ -1,18 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Solve::Dependency do
|
4
|
-
describe "
|
5
|
-
|
4
|
+
describe "#initialize" do
|
5
|
+
it "uses a default of >= 0.0.0" do
|
6
|
+
dep = Solve::Dependency.new(double("artifact"), "ntp")
|
6
7
|
|
7
|
-
|
8
|
-
|
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
|
8
|
+
expect(dep.constraint.operator).to eq(">=")
|
9
|
+
expect(dep.constraint.version.to_s).to eq("0.0.0")
|
16
10
|
end
|
17
11
|
end
|
18
12
|
|
@@ -22,43 +16,10 @@ describe Solve::Dependency do
|
|
22
16
|
|
23
17
|
subject { Solve::Dependency.new(artifact, name, constraint) }
|
24
18
|
|
25
|
-
describe "
|
26
|
-
context "given the dependency is a member of an artifact" do
|
27
|
-
subject { Solve::Dependency.new(artifact, name, constraint) }
|
28
|
-
|
29
|
-
before(:each) do
|
30
|
-
artifact.should_receive(:remove_dependency).with(subject).and_return(subject)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "notifies the artifact that the dependency should be removed" do
|
34
|
-
subject.delete
|
35
|
-
end
|
36
|
-
|
37
|
-
it "sets the artifact attribute to nil" do
|
38
|
-
subject.delete
|
39
|
-
|
40
|
-
subject.artifact.should be_nil
|
41
|
-
end
|
42
|
-
|
43
|
-
it "returns the instance of dependency deleted from the artifact" do
|
44
|
-
subject.delete.should eql(subject)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context "given the dependency is not the member of an artifact" do
|
49
|
-
subject { Solve::Dependency.new(nil, name, constraint) }
|
50
|
-
|
51
|
-
it "returns nil" do
|
52
|
-
subject.delete.should be_nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "#eql?" do
|
19
|
+
describe "#==" do
|
58
20
|
it "returns true if the other object is an instance of Solve::Dependency with the same constraint and artifact" do
|
59
21
|
other = Solve::Dependency.new(artifact, name, constraint)
|
60
|
-
|
61
|
-
subject.should eql(other)
|
22
|
+
expect(subject).to eq(other)
|
62
23
|
end
|
63
24
|
end
|
64
25
|
end
|
@@ -1,267 +1,130 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Solve::Graph do
|
4
|
-
describe "
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
4
|
+
describe "#artifact?" do
|
5
|
+
it "returns true if the given Solve::Artifact is a member of the collection" do
|
6
|
+
subject.artifact("nginx", "1.0.0")
|
7
|
+
expect(subject).to have_artifact("nginx", "1.0.0")
|
41
8
|
end
|
42
9
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
10
|
+
it "returns false if the given Solve::Artifact is not a member of the collection" do
|
11
|
+
expect(subject).to_not have_artifact("apache", "1.0.0")
|
12
|
+
expect(subject).to_not have_artifact("nginx", "11.4.4")
|
47
13
|
end
|
48
14
|
end
|
49
15
|
|
50
|
-
|
51
|
-
|
52
|
-
describe "#artifacts" do
|
53
|
-
context "given a name and version argument" do
|
54
|
-
let(:name) { "nginx" }
|
55
|
-
let(:version) { "0.101.5" }
|
56
|
-
|
57
|
-
context "given the artifact of the given name and version does not exist" do
|
58
|
-
it "returns a Solve::Artifact" do
|
59
|
-
subject.artifacts(name, version).should be_a(Solve::Artifact)
|
60
|
-
end
|
61
|
-
|
62
|
-
it "the artifact has the given name" do
|
63
|
-
subject.artifacts(name, version).name.should eql(name)
|
64
|
-
end
|
65
|
-
|
66
|
-
it "the artifact has the given version" do
|
67
|
-
subject.artifacts(name, version).version.to_s.should eql(version)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "adds an artifact to the artifacts collection" do
|
71
|
-
subject.artifacts(name, version)
|
16
|
+
describe "#find" do
|
17
|
+
before { subject.artifact("nginx", "1.0.0") }
|
72
18
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
it "the artifact added matches the given name" do
|
77
|
-
subject.artifacts(name, version)
|
78
|
-
|
79
|
-
subject.artifacts[0].name.should eql(name)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "the artifact added matches the given version" do
|
83
|
-
subject.artifacts(name, version)
|
19
|
+
it "returns an instance of artifact of the matching name and version" do
|
20
|
+
artifact = subject.find("nginx", "1.0.0")
|
84
21
|
|
85
|
-
|
86
|
-
|
87
|
-
|
22
|
+
expect(artifact).to be_a(Solve::Artifact)
|
23
|
+
expect(artifact.name).to eq("nginx")
|
24
|
+
expect(artifact.version.to_s).to eq("1.0.0")
|
88
25
|
end
|
89
26
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
it "returns an empty array if no artifacts have been accessed" do
|
96
|
-
subject.artifacts.should have(0).items
|
97
|
-
end
|
27
|
+
it "returns nil when the artifact does not exist" do
|
28
|
+
expect(subject.find("notthere", "1.0.0")).to be_nil
|
29
|
+
end
|
30
|
+
end
|
98
31
|
|
99
|
-
|
100
|
-
|
32
|
+
describe "#artifact" do
|
33
|
+
let(:name) { "nginx" }
|
34
|
+
let(:version) { "1.0.0" }
|
101
35
|
|
102
|
-
|
36
|
+
context "given the artifact of the given name and version does not exist" do
|
37
|
+
it "returns a Solve::Artifact" do
|
38
|
+
expect(subject.artifact(name, version)).to be_a(Solve::Artifact)
|
103
39
|
end
|
104
|
-
end
|
105
40
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
subject.artifacts(1, 2, 3)
|
110
|
-
}.should raise_error(ArgumentError, "Unexpected number of arguments. You gave: 3. Expected: 0 or 2.")
|
41
|
+
it "the artifact has the given name" do
|
42
|
+
artifact = subject.artifact(name, version)
|
43
|
+
expect(artifact.name).to eq(name)
|
111
44
|
end
|
112
45
|
|
113
|
-
it "
|
114
|
-
|
115
|
-
|
116
|
-
}.should raise_error(ArgumentError, "Unexpected number of arguments. You gave: 1. Expected: 0 or 2.")
|
46
|
+
it "the artifact has the given version" do
|
47
|
+
artifact = subject.artifact(name, version)
|
48
|
+
expect(artifact.version.to_s).to eq(version)
|
117
49
|
end
|
118
50
|
|
119
|
-
it "
|
120
|
-
|
121
|
-
|
122
|
-
}.should raise_error(ArgumentError, 'A name and version must be specified. You gave: ["nginx", nil].')
|
51
|
+
it "adds an artifact to the artifacts collection" do
|
52
|
+
subject.artifact(name, version)
|
53
|
+
expect(subject).to have_artifact(name, version)
|
123
54
|
end
|
124
55
|
end
|
125
56
|
end
|
126
57
|
|
127
|
-
describe "#
|
128
|
-
|
129
|
-
subject.artifacts(
|
58
|
+
describe "#artifacts" do
|
59
|
+
it "returns an array" do
|
60
|
+
expect(subject.artifacts).to be_a(Array)
|
130
61
|
end
|
131
62
|
|
132
|
-
it "returns an
|
133
|
-
|
134
|
-
|
135
|
-
artifact.should be_a(Solve::Artifact)
|
136
|
-
artifact.name.should eql("nginx")
|
137
|
-
artifact.version.to_s.should eql("1.0.0")
|
63
|
+
it "returns an empty array if no artifacts have been accessed" do
|
64
|
+
expect(subject.artifacts).to be_empty
|
138
65
|
end
|
139
66
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
end
|
67
|
+
it "returns an array containing an artifact if one was accessed" do
|
68
|
+
subject.artifact("nginx", "1.0.0")
|
69
|
+
expect(subject.artifacts.size).to eq(1)
|
144
70
|
end
|
145
71
|
end
|
146
72
|
|
147
73
|
describe "#versions" do
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
]
|
157
|
-
end
|
74
|
+
before do
|
75
|
+
subject.artifact('nginx', '1.0.0')
|
76
|
+
subject.artifact('nginx', '2.0.0')
|
77
|
+
subject.artifact('nginx', '3.0.0')
|
78
|
+
subject.artifact('nginx', '4.0.0')
|
158
79
|
|
159
|
-
|
160
|
-
subject.stub(:artifacts).and_return(artifacts)
|
80
|
+
subject.artifact('other', '1.0.0')
|
161
81
|
end
|
162
82
|
|
163
83
|
it "returns all the artifacts matching the given name" do
|
164
|
-
subject.versions("nginx").
|
165
|
-
end
|
166
|
-
|
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
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
describe "#add_artifact" do
|
175
|
-
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.0.0") }
|
176
|
-
|
177
|
-
it "adds a Solve::Artifact to the collection of artifacts" do
|
178
|
-
subject.add_artifact(artifact)
|
179
|
-
|
180
|
-
subject.should have_artifact(artifact.name, artifact.version)
|
181
|
-
subject.artifacts.should have(1).item
|
182
|
-
end
|
183
|
-
|
184
|
-
it "should not add the same artifact twice to the collection" do
|
185
|
-
subject.add_artifact(artifact)
|
186
|
-
subject.add_artifact(artifact)
|
187
|
-
|
188
|
-
subject.artifacts.should have(1).item
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
describe "#remove_artifact" do
|
193
|
-
let(:artifact) { Solve::Artifact.new(double('graph'), "nginx", "1.0.0") }
|
194
|
-
|
195
|
-
context "given the artifact is a member of the collection" do
|
196
|
-
before(:each) { subject.add_artifact(artifact) }
|
197
|
-
|
198
|
-
it "removes the Solve::Artifact from the collection of artifacts" do
|
199
|
-
subject.remove_artifact(artifact)
|
200
|
-
|
201
|
-
subject.artifacts.should have(0).items
|
202
|
-
end
|
203
|
-
|
204
|
-
it "returns the removed Solve::Artifact" do
|
205
|
-
subject.remove_artifact(artifact).should eql(artifact)
|
206
|
-
end
|
84
|
+
expect(subject.versions("nginx").size).to eq(4)
|
207
85
|
end
|
208
86
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
87
|
+
it "does not satisfy constraints if it is the default" do
|
88
|
+
constraint = Semverse::Constraint.new(Semverse::DEFAULT_CONSTRAINT.to_s)
|
89
|
+
expect(constraint).to_not receive(:satisfies?)
|
90
|
+
subject.versions("nginx")
|
213
91
|
end
|
214
|
-
end
|
215
92
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
it "returns true if the given Solve::Artifact is a member of the collection" do
|
220
|
-
subject.add_artifact(artifact)
|
221
|
-
|
222
|
-
subject.has_artifact?(artifact.name, artifact.version).should be_true
|
223
|
-
end
|
224
|
-
|
225
|
-
it "returns false if the given Solve::Artifact is not a member of the collection" do
|
226
|
-
subject.has_artifact?(artifact.name, artifact.version).should be_false
|
93
|
+
it "returns only matching constraints if one is given" do
|
94
|
+
expect(subject.versions("nginx", ">= 3.0.0").size).to eq(2)
|
227
95
|
end
|
228
96
|
end
|
229
97
|
|
230
|
-
describe "
|
231
|
-
|
98
|
+
describe "==" do
|
99
|
+
def make_graph
|
232
100
|
graph = Solve::Graph.new
|
233
|
-
graph.
|
234
|
-
graph.
|
101
|
+
graph.artifact("A" ,"1.0.0").depends("B", "1.0.0")
|
102
|
+
graph.artifact("A" ,"2.0.0").depends("C", "1.0.0")
|
235
103
|
graph
|
236
104
|
end
|
237
105
|
|
106
|
+
subject { make_graph }
|
107
|
+
|
238
108
|
it "returns false if other isn't a Solve::Graph" do
|
239
|
-
subject.
|
109
|
+
expect(subject).to_not eq("chicken")
|
240
110
|
end
|
241
111
|
|
242
|
-
it "returns true if other is
|
243
|
-
|
244
|
-
other.artifacts("A", "1.0.0").depends("B", "1.0.0")
|
245
|
-
other.artifacts("A", "2.0.0").depends("C", "1.0.0")
|
246
|
-
|
247
|
-
subject.should eql(other)
|
112
|
+
it "returns true if the other is the same" do
|
113
|
+
expect(subject).to eq(make_graph)
|
248
114
|
end
|
249
115
|
|
250
|
-
it "returns false if the other
|
251
|
-
other =
|
252
|
-
other.
|
253
|
-
other.artifacts("A", "2.0.0")
|
116
|
+
it "returns false if the other has the same artifacts but different dependencies" do
|
117
|
+
other = make_graph
|
118
|
+
other.artifact("A", "1.0.0").depends("D", "1.0.0")
|
254
119
|
|
255
|
-
subject.
|
120
|
+
expect(subject).to_not eq(other)
|
256
121
|
end
|
257
122
|
|
258
|
-
it "returns false if the other
|
259
|
-
other =
|
260
|
-
other.
|
261
|
-
other.artifacts("A", "2.0.0").depends("C", "1.0.0")
|
262
|
-
other.artifacts("B", "1.0.0")
|
123
|
+
it "returns false if the other has the same dependencies but different artifacts" do
|
124
|
+
other = make_graph
|
125
|
+
other.artifact("E", "1.0.0")
|
263
126
|
|
264
|
-
subject.
|
127
|
+
expect(subject).to_not eq(other)
|
265
128
|
end
|
266
129
|
end
|
267
130
|
end
|