solve 4.0.0 → 4.0.1
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 +5 -5
- data/lib/solve/constraint.rb +1 -1
- data/lib/solve/gecode_solver.rb +1 -1
- data/lib/solve/ruby_solver.rb +1 -1
- data/lib/solve/version.rb +1 -1
- metadata +5 -42
- data/.gitignore +0 -20
- data/.travis.yml +0 -25
- data/Gemfile +0 -36
- data/Guardfile +0 -17
- data/NoGecode.gemfile +0 -4
- data/README.md +0 -85
- data/Rakefile +0 -11
- data/Thorfile +0 -36
- data/solve.gemspec +0 -26
- data/spec/acceptance/benchmark.rb +0 -59
- data/spec/acceptance/large_graph_no_solution.rb +0 -18730
- data/spec/acceptance/opscode_ci_graph.rb +0 -18600
- data/spec/acceptance/ruby_solver_solutions_spec.rb +0 -306
- data/spec/acceptance/solutions_spec.rb +0 -316
- data/spec/spec_helper.rb +0 -32
- data/spec/unit/solve/artifact_spec.rb +0 -137
- data/spec/unit/solve/demand_spec.rb +0 -53
- data/spec/unit/solve/dependency_spec.rb +0 -25
- data/spec/unit/solve/gecode_solver_spec.rb +0 -205
- data/spec/unit/solve/graph_spec.rb +0 -130
- data/spec/unit/solve/ruby_solver_spec.rb +0 -165
- data/spec/unit/solve/solver/serializer_spec.rb +0 -33
- data/spec/unit/solve_spec.rb +0 -19
@@ -1,306 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe "Solutions when using the ruby solver" do
|
4
|
-
|
5
|
-
before do
|
6
|
-
Solve.engine = :ruby
|
7
|
-
end
|
8
|
-
|
9
|
-
it "chooses the correct artifact for the demands" do
|
10
|
-
graph = Solve::Graph.new
|
11
|
-
graph.artifact("mysql", "2.0.0")
|
12
|
-
graph.artifact("mysql", "1.2.0")
|
13
|
-
graph.artifact("nginx", "1.0.0").depends("mysql", "= 1.2.0")
|
14
|
-
|
15
|
-
result = Solve.it!(graph, [["nginx", "= 1.0.0"], ["mysql"]])
|
16
|
-
|
17
|
-
result.should eql("nginx" => "1.0.0", "mysql" => "1.2.0")
|
18
|
-
end
|
19
|
-
|
20
|
-
it "chooses the best artifact for the demands" do
|
21
|
-
graph = Solve::Graph.new
|
22
|
-
graph.artifact("mysql", "2.0.0")
|
23
|
-
graph.artifact("mysql", "1.2.0")
|
24
|
-
graph.artifact("nginx", "1.0.0").depends("mysql", ">= 1.2.0")
|
25
|
-
|
26
|
-
result = Solve.it!(graph, [["nginx", "= 1.0.0"], ["mysql"]])
|
27
|
-
|
28
|
-
result.should eql("nginx" => "1.0.0", "mysql" => "2.0.0")
|
29
|
-
end
|
30
|
-
|
31
|
-
it "raises NoSolutionError when a solution cannot be found" do
|
32
|
-
graph = Solve::Graph.new
|
33
|
-
graph.artifact("mysql", "1.2.0")
|
34
|
-
|
35
|
-
lambda {
|
36
|
-
Solve.it!(graph, ["mysql", ">= 2.0.0"])
|
37
|
-
}.should raise_error(Solve::Errors::NoSolutionError)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "find the correct solution when backtracking in variables introduced via demands" do
|
41
|
-
graph = Solve::Graph.new
|
42
|
-
|
43
|
-
graph.artifact("D", "1.2.0")
|
44
|
-
graph.artifact("D", "1.3.0")
|
45
|
-
graph.artifact("D", "1.4.0")
|
46
|
-
graph.artifact("D", "2.0.0")
|
47
|
-
graph.artifact("D", "2.1.0")
|
48
|
-
|
49
|
-
graph.artifact("C", "2.0.0").depends("D", "= 1.2.0")
|
50
|
-
graph.artifact("C", "2.1.0").depends("D", ">= 2.1.0")
|
51
|
-
graph.artifact("C", "2.2.0").depends("D", "> 2.0.0")
|
52
|
-
|
53
|
-
graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
|
54
|
-
graph.artifact("B", "1.1.0").depends("D", "= 1.0.0")
|
55
|
-
graph.artifact("B", "2.0.0").depends("D", ">= 1.3.0")
|
56
|
-
graph.artifact("B", "2.1.0").depends("D", ">= 2.0.0")
|
57
|
-
|
58
|
-
graph.artifact("A", "1.0.0").depends("B", "> 2.0.0")
|
59
|
-
graph.artifact("A", "1.0.0").depends("C", "= 2.1.0")
|
60
|
-
graph.artifact("A", "1.0.1").depends("B", "> 1.0.0")
|
61
|
-
graph.artifact("A", "1.0.1").depends("C", "= 2.1.0")
|
62
|
-
graph.artifact("A", "1.0.2").depends("B", "> 1.0.0")
|
63
|
-
graph.artifact("A", "1.0.2").depends("C", "= 2.0.0")
|
64
|
-
|
65
|
-
result = Solve.it!(graph, [["A", "~> 1.0.0"], ["D", ">= 2.0.0"]])
|
66
|
-
|
67
|
-
result.should eql("A" => "1.0.1",
|
68
|
-
"B" => "2.1.0",
|
69
|
-
"C" => "2.1.0",
|
70
|
-
"D" => "2.1.0")
|
71
|
-
end
|
72
|
-
|
73
|
-
it "rejects a circular dependency with a circular dep error" do
|
74
|
-
graph = Solve::Graph.new
|
75
|
-
|
76
|
-
graph.artifact("A", "1.0.0").depends("B", "1.0.0")
|
77
|
-
graph.artifact("B", "1.0.0").depends("C", "1.0.0")
|
78
|
-
graph.artifact("C", "1.0.0").depends("A", "1.0.0")
|
79
|
-
|
80
|
-
expect { Solve.it!(graph, [["A", "1.0.0"]]) }.to raise_error(Solve::Errors::NoSolutionError)
|
81
|
-
end
|
82
|
-
|
83
|
-
it "rejects a p shaped depenency chain with a circular dep error" do
|
84
|
-
graph = Solve::Graph.new
|
85
|
-
|
86
|
-
graph.artifact("A", "1.0.0").depends("B", "1.0.0")
|
87
|
-
graph.artifact("B", "1.0.0").depends("C", "1.0.0")
|
88
|
-
graph.artifact("C", "1.0.0").depends("B", "1.0.0")
|
89
|
-
|
90
|
-
expect { Solve.it!(graph, [["A", "1.0.0"]]) }.to raise_error(Solve::Errors::NoSolutionError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it "finds the correct solution when there is a diamond shaped dependency" do
|
94
|
-
graph = Solve::Graph.new
|
95
|
-
|
96
|
-
graph.artifact("A", "1.0.0")
|
97
|
-
.depends("B", "1.0.0")
|
98
|
-
.depends("C", "1.0.0")
|
99
|
-
graph.artifact("B", "1.0.0")
|
100
|
-
.depends("D", "1.0.0")
|
101
|
-
graph.artifact("C", "1.0.0")
|
102
|
-
.depends("D", "1.0.0")
|
103
|
-
graph.artifact("D", "1.0.0")
|
104
|
-
|
105
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
106
|
-
|
107
|
-
result.should eql("A" => "1.0.0",
|
108
|
-
"B" => "1.0.0",
|
109
|
-
"C" => "1.0.0",
|
110
|
-
"D" => "1.0.0")
|
111
|
-
end
|
112
|
-
|
113
|
-
it "solves when packages and constraints have prerelease elements" do
|
114
|
-
graph = Solve::Graph.new
|
115
|
-
|
116
|
-
graph.artifact("A", "1.0.0")
|
117
|
-
.depends("B", ">= 1.0.0-alpha")
|
118
|
-
graph.artifact("B", "1.0.0-alpha")
|
119
|
-
.depends("C", "1.0.0")
|
120
|
-
graph.artifact("C", "1.0.0")
|
121
|
-
|
122
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
123
|
-
|
124
|
-
result.should eql("A" => "1.0.0",
|
125
|
-
"B" => "1.0.0-alpha",
|
126
|
-
"C" => "1.0.0")
|
127
|
-
|
128
|
-
end
|
129
|
-
|
130
|
-
it "solves when packages and constraints have build elements" do
|
131
|
-
graph = Solve::Graph.new
|
132
|
-
|
133
|
-
graph.artifact("A", "1.0.0")
|
134
|
-
.depends("B", ">= 1.0.0+build")
|
135
|
-
graph.artifact("B", "1.0.0+build")
|
136
|
-
.depends("C", "1.0.0")
|
137
|
-
graph.artifact("C", "1.0.0")
|
138
|
-
|
139
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
140
|
-
|
141
|
-
result.should eql("A" => "1.0.0",
|
142
|
-
"B" => "1.0.0+build",
|
143
|
-
"C" => "1.0.0")
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
it "fails with a self dependency" do
|
148
|
-
graph = Solve::Graph.new
|
149
|
-
|
150
|
-
graph.artifact("bottom", "1.0.0")
|
151
|
-
graph.artifact("middle", "1.0.0").depends("top", "= 1.0.0").depends("middle")
|
152
|
-
|
153
|
-
demands = [["bottom", "1.0.0"], ["middle", "1.0.0"]]
|
154
|
-
|
155
|
-
expect { Solve.it!(graph, demands, { :sorted => true } ) }.to raise_error { |error|
|
156
|
-
error.should be_a(Solve::Errors::NoSolutionError)
|
157
|
-
}
|
158
|
-
end
|
159
|
-
|
160
|
-
it "gives an empty solution when there are no demands" do
|
161
|
-
graph = Solve::Graph.new
|
162
|
-
result = Solve.it!(graph, [])
|
163
|
-
result.should eql({})
|
164
|
-
end
|
165
|
-
|
166
|
-
it "tries all combinations until it finds a solution" do
|
167
|
-
|
168
|
-
graph = Solve::Graph.new
|
169
|
-
|
170
|
-
graph.artifact("A", "1.0.0").depends("B", "~> 1.0.0")
|
171
|
-
graph.artifact("A", "1.0.1").depends("B", "~> 1.0.0")
|
172
|
-
graph.artifact("A", "1.0.2").depends("B", "~> 1.0.0")
|
173
|
-
|
174
|
-
graph.artifact("B", "1.0.0").depends("C", "~> 1.0.0")
|
175
|
-
graph.artifact("B", "1.0.1").depends("C", "~> 1.0.0")
|
176
|
-
graph.artifact("B", "1.0.2").depends("C", "~> 1.0.0")
|
177
|
-
|
178
|
-
graph.artifact("C", "1.0.0").depends("D", "1.0.0")
|
179
|
-
graph.artifact("C", "1.0.1").depends("D", "1.0.0")
|
180
|
-
graph.artifact("C", "1.0.2").depends("D", "1.0.0")
|
181
|
-
|
182
|
-
# Note:
|
183
|
-
# This test previously used two circular dependencies:
|
184
|
-
# (D 1.0.0) -> A < 0.0.0
|
185
|
-
# (D 0.0.0) -> A = 0.0.0
|
186
|
-
# But Molinillo doesn't support circular dependencies at all.
|
187
|
-
|
188
|
-
# ensure we can't find a solution in the above
|
189
|
-
graph.artifact("D", "1.0.0").depends("E", "< 0.0.0")
|
190
|
-
|
191
|
-
# Add a solution to the graph that should be reached only after all of the
|
192
|
-
# others have been tried
|
193
|
-
graph.artifact("A", "0.0.0").depends("B", "0.0.0")
|
194
|
-
graph.artifact("B", "0.0.0").depends("C", "0.0.0")
|
195
|
-
graph.artifact("C", "0.0.0").depends("D", "0.0.0")
|
196
|
-
graph.artifact("D", "0.0.0")
|
197
|
-
|
198
|
-
demands = [["A"]]
|
199
|
-
|
200
|
-
result = Solve.it!(graph, demands)
|
201
|
-
|
202
|
-
result.should eql({ "A" => "0.0.0",
|
203
|
-
"B" => "0.0.0",
|
204
|
-
"C" => "0.0.0",
|
205
|
-
"D" => "0.0.0" })
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
it "correctly resolves when a resolution exists but it is not the latest" do
|
210
|
-
graph = Solve::Graph.new
|
211
|
-
|
212
|
-
graph.artifact("get-the-old-one", "1.0.0")
|
213
|
-
.depends("locked-mid-1", ">= 0.0.0")
|
214
|
-
.depends("locked-mid-2", ">= 0.0.0")
|
215
|
-
graph.artifact("get-the-old-one", "0.5.0")
|
216
|
-
|
217
|
-
graph.artifact("locked-mid-1", "2.0.0").depends("old-bottom", "= 2.0.0")
|
218
|
-
graph.artifact("locked-mid-1", "1.3.0").depends("old-bottom", "= 0.5.0")
|
219
|
-
graph.artifact("locked-mid-1", "1.0.0")
|
220
|
-
|
221
|
-
graph.artifact("locked-mid-2", "2.0.0").depends("old-bottom", "= 2.1.0")
|
222
|
-
graph.artifact("locked-mid-2", "1.4.0").depends("old-bottom", "= 0.5.0")
|
223
|
-
graph.artifact("locked-mid-2", "1.0.0")
|
224
|
-
|
225
|
-
graph.artifact("old-bottom", "2.1.0")
|
226
|
-
graph.artifact("old-bottom", "2.0.0")
|
227
|
-
graph.artifact("old-bottom", "1.0.0")
|
228
|
-
graph.artifact("old-bottom", "0.5.0")
|
229
|
-
|
230
|
-
demands = [["get-the-old-one"]]
|
231
|
-
|
232
|
-
result = Solve.it!(graph, demands)
|
233
|
-
|
234
|
-
# Note: Gecode solver is different. It picks:
|
235
|
-
#
|
236
|
-
# "get-the-old-one" => "1.0.0",
|
237
|
-
# "locked-mid-1" => "1.0.0",
|
238
|
-
# "locked-mid-2" => "2.0.0",
|
239
|
-
# "old-bottom" => "2.1.0"
|
240
|
-
|
241
|
-
result.should eql({
|
242
|
-
"get-the-old-one" => "1.0.0",
|
243
|
-
"locked-mid-1" => "2.0.0",
|
244
|
-
"locked-mid-2" => "1.0.0",
|
245
|
-
"old-bottom" => "2.0.0",
|
246
|
-
})
|
247
|
-
end
|
248
|
-
|
249
|
-
describe "when options[:sorted] is true" do
|
250
|
-
describe "with a simple list of dependencies" do
|
251
|
-
it "returns a sorted list of dependencies" do
|
252
|
-
graph = Solve::Graph.new
|
253
|
-
|
254
|
-
graph.artifact("A", "1.0.0").depends("B", "= 1.0.0")
|
255
|
-
graph.artifact("B", "1.0.0").depends("C", "= 1.0.0")
|
256
|
-
graph.artifact("C", "1.0.0")
|
257
|
-
|
258
|
-
demands = [["A"]]
|
259
|
-
|
260
|
-
result = Solve.it!(graph, demands, { :sorted => true })
|
261
|
-
|
262
|
-
result.should eql([
|
263
|
-
["C", "1.0.0"],
|
264
|
-
["B", "1.0.0"],
|
265
|
-
["A", "1.0.0"],
|
266
|
-
])
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
# The order that the demands come in determines the order of artifacts
|
271
|
-
# in the solver's variable_table. This must not determine the sort order
|
272
|
-
describe "with a constraint that depends upon an earlier constrained artifact" do
|
273
|
-
it "returns a sorted list of dependencies" do
|
274
|
-
graph = Solve::Graph.new
|
275
|
-
|
276
|
-
graph.artifact("B", "1.0.0").depends("A", "= 1.0.0")
|
277
|
-
graph.artifact("A", "1.0.0").depends("C", "= 1.0.0")
|
278
|
-
graph.artifact("C", "1.0.0")
|
279
|
-
|
280
|
-
demands = [["A"], ["B"]]
|
281
|
-
|
282
|
-
result = Solve.it!(graph, demands, { :sorted => true } )
|
283
|
-
|
284
|
-
result.should eql([
|
285
|
-
["C", "1.0.0"],
|
286
|
-
["A", "1.0.0"],
|
287
|
-
["B", "1.0.0"],
|
288
|
-
])
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
describe "when the solution is cyclic" do
|
293
|
-
it "raises a Solve::Errors::NoSolutionError because Molinillo doesn't support circular deps" do
|
294
|
-
graph = Solve::Graph.new
|
295
|
-
|
296
|
-
graph.artifact("A", "1.0.0").depends("B", "= 1.0.0")
|
297
|
-
graph.artifact("B", "1.0.0").depends("C", "= 1.0.0")
|
298
|
-
graph.artifact("C", "1.0.0").depends("A", "= 1.0.0")
|
299
|
-
|
300
|
-
demands = [["A"]]
|
301
|
-
|
302
|
-
expect { Solve.it!(graph, demands, { :sorted => true } ) }.to raise_error(Solve::Errors::NoSolutionError)
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
@@ -1,316 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe "Solutions", :gecode do
|
4
|
-
|
5
|
-
before do
|
6
|
-
Solve.engine = :gecode
|
7
|
-
end
|
8
|
-
|
9
|
-
it "chooses the correct artifact for the demands" do
|
10
|
-
graph = Solve::Graph.new
|
11
|
-
graph.artifact("mysql", "2.0.0")
|
12
|
-
graph.artifact("mysql", "1.2.0")
|
13
|
-
graph.artifact("nginx", "1.0.0").depends("mysql", "= 1.2.0")
|
14
|
-
|
15
|
-
result = Solve.it!(graph, [["nginx", "= 1.0.0"], ["mysql"]])
|
16
|
-
|
17
|
-
result.should eql("nginx" => "1.0.0", "mysql" => "1.2.0")
|
18
|
-
end
|
19
|
-
|
20
|
-
it "chooses the best artifact for the demands" do
|
21
|
-
graph = Solve::Graph.new
|
22
|
-
graph.artifact("mysql", "2.0.0")
|
23
|
-
graph.artifact("mysql", "1.2.0")
|
24
|
-
graph.artifact("nginx", "1.0.0").depends("mysql", ">= 1.2.0")
|
25
|
-
|
26
|
-
result = Solve.it!(graph, [["nginx", "= 1.0.0"], ["mysql"]])
|
27
|
-
|
28
|
-
result.should eql("nginx" => "1.0.0", "mysql" => "2.0.0")
|
29
|
-
end
|
30
|
-
|
31
|
-
it "raises NoSolutionError when a solution cannot be found" do
|
32
|
-
graph = Solve::Graph.new
|
33
|
-
graph.artifact("mysql", "1.2.0")
|
34
|
-
|
35
|
-
lambda {
|
36
|
-
Solve.it!(graph, ["mysql", ">= 2.0.0"])
|
37
|
-
}.should raise_error(Solve::Errors::NoSolutionError)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "find the correct solution when backtracking in variables introduced via demands" do
|
41
|
-
graph = Solve::Graph.new
|
42
|
-
|
43
|
-
graph.artifact("D", "1.2.0")
|
44
|
-
graph.artifact("D", "1.3.0")
|
45
|
-
graph.artifact("D", "1.4.0")
|
46
|
-
graph.artifact("D", "2.0.0")
|
47
|
-
graph.artifact("D", "2.1.0")
|
48
|
-
|
49
|
-
graph.artifact("C", "2.0.0").depends("D", "= 1.2.0")
|
50
|
-
graph.artifact("C", "2.1.0").depends("D", ">= 2.1.0")
|
51
|
-
graph.artifact("C", "2.2.0").depends("D", "> 2.0.0")
|
52
|
-
|
53
|
-
graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
|
54
|
-
graph.artifact("B", "1.1.0").depends("D", "= 1.0.0")
|
55
|
-
graph.artifact("B", "2.0.0").depends("D", ">= 1.3.0")
|
56
|
-
graph.artifact("B", "2.1.0").depends("D", ">= 2.0.0")
|
57
|
-
|
58
|
-
graph.artifact("A", "1.0.0").depends("B", "> 2.0.0")
|
59
|
-
graph.artifact("A", "1.0.0").depends("C", "= 2.1.0")
|
60
|
-
graph.artifact("A", "1.0.1").depends("B", "> 1.0.0")
|
61
|
-
graph.artifact("A", "1.0.1").depends("C", "= 2.1.0")
|
62
|
-
graph.artifact("A", "1.0.2").depends("B", "> 1.0.0")
|
63
|
-
graph.artifact("A", "1.0.2").depends("C", "= 2.0.0")
|
64
|
-
|
65
|
-
result = Solve.it!(graph, [["A", "~> 1.0.0"], ["D", ">= 2.0.0"]])
|
66
|
-
|
67
|
-
result.should eql("A" => "1.0.1",
|
68
|
-
"B" => "2.1.0",
|
69
|
-
"C" => "2.1.0",
|
70
|
-
"D" => "2.1.0")
|
71
|
-
end
|
72
|
-
|
73
|
-
it "finds the correct solution when there is a circular dependency" do
|
74
|
-
graph = Solve::Graph.new
|
75
|
-
|
76
|
-
graph.artifact("A", "1.0.0").depends("B", "1.0.0")
|
77
|
-
graph.artifact("B", "1.0.0").depends("C", "1.0.0")
|
78
|
-
graph.artifact("C", "1.0.0").depends("A", "1.0.0")
|
79
|
-
|
80
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
81
|
-
|
82
|
-
result.should eql("A" => "1.0.0",
|
83
|
-
"B" => "1.0.0",
|
84
|
-
"C" => "1.0.0")
|
85
|
-
end
|
86
|
-
|
87
|
-
it "finds the correct solution when there is a p shaped depenency chain" do
|
88
|
-
graph = Solve::Graph.new
|
89
|
-
|
90
|
-
graph.artifact("A", "1.0.0").depends("B", "1.0.0")
|
91
|
-
graph.artifact("B", "1.0.0").depends("C", "1.0.0")
|
92
|
-
graph.artifact("C", "1.0.0").depends("B", "1.0.0")
|
93
|
-
|
94
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
95
|
-
|
96
|
-
result.should eql("A" => "1.0.0",
|
97
|
-
"B" => "1.0.0",
|
98
|
-
"C" => "1.0.0")
|
99
|
-
end
|
100
|
-
|
101
|
-
it "finds the correct solution when there is a diamond shaped dependency" do
|
102
|
-
graph = Solve::Graph.new
|
103
|
-
|
104
|
-
graph.artifact("A", "1.0.0")
|
105
|
-
.depends("B", "1.0.0")
|
106
|
-
.depends("C", "1.0.0")
|
107
|
-
graph.artifact("B", "1.0.0")
|
108
|
-
.depends("D", "1.0.0")
|
109
|
-
graph.artifact("C", "1.0.0")
|
110
|
-
.depends("D", "1.0.0")
|
111
|
-
graph.artifact("D", "1.0.0")
|
112
|
-
|
113
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
114
|
-
|
115
|
-
result.should eql("A" => "1.0.0",
|
116
|
-
"B" => "1.0.0",
|
117
|
-
"C" => "1.0.0",
|
118
|
-
"D" => "1.0.0")
|
119
|
-
end
|
120
|
-
|
121
|
-
it "solves when packages and constraints have prerelease elements" do
|
122
|
-
graph = Solve::Graph.new
|
123
|
-
|
124
|
-
graph.artifact("A", "1.0.0")
|
125
|
-
.depends("B", ">= 1.0.0-alpha")
|
126
|
-
graph.artifact("B", "1.0.0-alpha")
|
127
|
-
.depends("C", "1.0.0")
|
128
|
-
graph.artifact("C", "1.0.0")
|
129
|
-
|
130
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
131
|
-
|
132
|
-
result.should eql("A" => "1.0.0",
|
133
|
-
"B" => "1.0.0-alpha",
|
134
|
-
"C" => "1.0.0")
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
it "solves when packages and constraints have build elements" do
|
139
|
-
graph = Solve::Graph.new
|
140
|
-
|
141
|
-
graph.artifact("A", "1.0.0")
|
142
|
-
.depends("B", ">= 1.0.0+build")
|
143
|
-
graph.artifact("B", "1.0.0+build")
|
144
|
-
.depends("C", "1.0.0")
|
145
|
-
graph.artifact("C", "1.0.0")
|
146
|
-
|
147
|
-
result = Solve.it!(graph, [["A", "1.0.0"]])
|
148
|
-
|
149
|
-
result.should eql("A" => "1.0.0",
|
150
|
-
"B" => "1.0.0+build",
|
151
|
-
"C" => "1.0.0")
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
it "fails with a self dependency" do
|
156
|
-
graph = Solve::Graph.new
|
157
|
-
|
158
|
-
graph.artifact("bottom", "1.0.0")
|
159
|
-
graph.artifact("middle", "1.0.0").depends("top", "= 1.0.0").depends("middle")
|
160
|
-
|
161
|
-
demands = [["bottom", "1.0.0"], ["middle", "1.0.0"]]
|
162
|
-
|
163
|
-
expect { Solve.it!(graph, demands, { :sorted => true } ) }.to raise_error { |error|
|
164
|
-
error.should be_a(Solve::Errors::NoSolutionError)
|
165
|
-
}
|
166
|
-
end
|
167
|
-
|
168
|
-
it "gives an empty solution when there are no demands" do
|
169
|
-
graph = Solve::Graph.new
|
170
|
-
result = Solve.it!(graph, [])
|
171
|
-
result.should eql({})
|
172
|
-
end
|
173
|
-
|
174
|
-
it "tries all combinations until it finds a solution" do
|
175
|
-
|
176
|
-
graph = Solve::Graph.new
|
177
|
-
|
178
|
-
graph.artifact("A", "1.0.0").depends("B", "~> 1.0.0")
|
179
|
-
graph.artifact("A", "1.0.1").depends("B", "~> 1.0.0")
|
180
|
-
graph.artifact("A", "1.0.2").depends("B", "~> 1.0.0")
|
181
|
-
|
182
|
-
graph.artifact("B", "1.0.0").depends("C", "~> 1.0.0")
|
183
|
-
graph.artifact("B", "1.0.1").depends("C", "~> 1.0.0")
|
184
|
-
graph.artifact("B", "1.0.2").depends("C", "~> 1.0.0")
|
185
|
-
|
186
|
-
graph.artifact("C", "1.0.0").depends("D", "1.0.0")
|
187
|
-
graph.artifact("C", "1.0.1").depends("D", "1.0.0")
|
188
|
-
graph.artifact("C", "1.0.2").depends("D", "1.0.0")
|
189
|
-
|
190
|
-
# ensure we can't find a solution in the above
|
191
|
-
graph.artifact("D", "1.0.0").depends("A", "< 0.0.0")
|
192
|
-
|
193
|
-
# Add a solution to the graph that should be reached only after
|
194
|
-
# all of the others have been tried
|
195
|
-
# it must be circular to ensure that no other branch can find it
|
196
|
-
graph.artifact("A", "0.0.0").depends("B", "0.0.0")
|
197
|
-
graph.artifact("B", "0.0.0").depends("C", "0.0.0")
|
198
|
-
graph.artifact("C", "0.0.0").depends("D", "0.0.0")
|
199
|
-
graph.artifact("D", "0.0.0").depends("A", "0.0.0")
|
200
|
-
|
201
|
-
demands = [["A"]]
|
202
|
-
|
203
|
-
result = Solve.it!(graph, demands)
|
204
|
-
|
205
|
-
result.should eql({ "A" => "0.0.0",
|
206
|
-
"B" => "0.0.0",
|
207
|
-
"C" => "0.0.0",
|
208
|
-
"D" => "0.0.0" })
|
209
|
-
|
210
|
-
end
|
211
|
-
|
212
|
-
it "correctly resolves when a resolution exists but it is not the latest" do
|
213
|
-
graph = Solve::Graph.new
|
214
|
-
|
215
|
-
graph.artifact("get-the-old-one", "1.0.0")
|
216
|
-
.depends("locked-mid-1", ">= 0.0.0")
|
217
|
-
.depends("locked-mid-2", ">= 0.0.0")
|
218
|
-
graph.artifact("get-the-old-one", "0.5.0")
|
219
|
-
|
220
|
-
graph.artifact("locked-mid-1", "2.0.0").depends("old-bottom", "= 2.0.0")
|
221
|
-
graph.artifact("locked-mid-1", "1.3.0").depends("old-bottom", "= 0.5.0")
|
222
|
-
graph.artifact("locked-mid-1", "1.0.0")
|
223
|
-
|
224
|
-
graph.artifact("locked-mid-2", "2.0.0").depends("old-bottom", "= 2.1.0")
|
225
|
-
graph.artifact("locked-mid-2", "1.4.0").depends("old-bottom", "= 0.5.0")
|
226
|
-
graph.artifact("locked-mid-2", "1.0.0")
|
227
|
-
|
228
|
-
graph.artifact("old-bottom", "2.1.0")
|
229
|
-
graph.artifact("old-bottom", "2.0.0")
|
230
|
-
graph.artifact("old-bottom", "1.0.0")
|
231
|
-
graph.artifact("old-bottom", "0.5.0")
|
232
|
-
|
233
|
-
demands = [["get-the-old-one"]]
|
234
|
-
|
235
|
-
result = Solve.it!(graph, demands)
|
236
|
-
|
237
|
-
# ruby solver result:
|
238
|
-
#
|
239
|
-
# "get-the-old-one" => "1.0.0",
|
240
|
-
# "locked-mid-1" => "2.0.0",
|
241
|
-
# "locked-mid-2" => "1.0.0",
|
242
|
-
# "old-bottom" => "2.0.0"
|
243
|
-
|
244
|
-
result.should eql({
|
245
|
-
"get-the-old-one" => "1.0.0",
|
246
|
-
"locked-mid-1" => "1.0.0",
|
247
|
-
"locked-mid-2" => "2.0.0",
|
248
|
-
"old-bottom" => "2.1.0",
|
249
|
-
})
|
250
|
-
end
|
251
|
-
|
252
|
-
describe "when options[:sorted] is true" do
|
253
|
-
describe "with a simple list of dependencies" do
|
254
|
-
it "returns a sorted list of dependencies" do
|
255
|
-
graph = Solve::Graph.new
|
256
|
-
|
257
|
-
graph.artifact("A", "1.0.0").depends("B", "= 1.0.0")
|
258
|
-
graph.artifact("B", "1.0.0").depends("C", "= 1.0.0")
|
259
|
-
graph.artifact("C", "1.0.0")
|
260
|
-
|
261
|
-
demands = [["A"]]
|
262
|
-
|
263
|
-
result = Solve.it!(graph, demands, { :sorted => true })
|
264
|
-
|
265
|
-
result.should eql([
|
266
|
-
["C", "1.0.0"],
|
267
|
-
["B", "1.0.0"],
|
268
|
-
["A", "1.0.0"],
|
269
|
-
])
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
# The order that the demands come in determines the order of artifacts
|
274
|
-
# in the solver's variable_table. This must not determine the sort order
|
275
|
-
describe "with a constraint that depends upon an earlier constrained artifact" do
|
276
|
-
it "returns a sorted list of dependencies" do
|
277
|
-
graph = Solve::Graph.new
|
278
|
-
|
279
|
-
graph.artifact("B", "1.0.0").depends("A", "= 1.0.0")
|
280
|
-
graph.artifact("A", "1.0.0").depends("C", "= 1.0.0")
|
281
|
-
graph.artifact("C", "1.0.0")
|
282
|
-
|
283
|
-
demands = [["A"], ["B"]]
|
284
|
-
|
285
|
-
result = Solve.it!(graph, demands, { :sorted => true } )
|
286
|
-
|
287
|
-
result.should eql([
|
288
|
-
["C", "1.0.0"],
|
289
|
-
["A", "1.0.0"],
|
290
|
-
["B", "1.0.0"],
|
291
|
-
])
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
describe "when the solution is cyclic" do
|
296
|
-
it "raises a Solve::Errors::UnsortableSolutionError which contains the unsorted solution" do
|
297
|
-
graph = Solve::Graph.new
|
298
|
-
|
299
|
-
graph.artifact("A", "1.0.0").depends("B", "= 1.0.0")
|
300
|
-
graph.artifact("B", "1.0.0").depends("C", "= 1.0.0")
|
301
|
-
graph.artifact("C", "1.0.0").depends("A", "= 1.0.0")
|
302
|
-
|
303
|
-
demands = [["A"]]
|
304
|
-
|
305
|
-
expect { Solve.it!(graph, demands, { :sorted => true } ) }.to raise_error { |error|
|
306
|
-
error.should be_a(Solve::Errors::UnsortableSolutionError)
|
307
|
-
error.unsorted_solution.should eql({
|
308
|
-
"A" => "1.0.0",
|
309
|
-
"B" => "1.0.0",
|
310
|
-
"C" => "1.0.0",
|
311
|
-
})
|
312
|
-
}
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|