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.
@@ -2,12 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe Solve::Solver::Serializer do
4
4
  it "deserializes a serialized solver to an equivalent solver" do
5
-
6
5
  graph = Solve::Graph.new
7
6
 
8
- graph.artifacts("A", "1.0.0").depends("B", "1.0.0")
9
- graph.artifacts("B", "1.0.0").depends("C", "1.0.0")
10
- graph.artifacts("C", "1.0.0")
7
+ graph.artifact("A", "1.0.0").depends("B", "1.0.0")
8
+ graph.artifact("B", "1.0.0").depends("C", "1.0.0")
9
+ graph.artifact("C", "1.0.0")
11
10
 
12
11
  demands = [["A", "1.0.0"]]
13
12
 
@@ -1,302 +1,158 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Solve::Solver do
4
- let(:graph) { double('graph') }
4
+ let(:graph) { double(Solve::Graph) }
5
+ let(:demands) { [["mysql"], ["nginx"]] }
6
+ subject(:solver) { described_class.new(graph, demands) }
5
7
 
6
- describe "ClassMethods" do
7
- subject { Solve::Solver }
8
-
9
- describe "::new" do
10
- let(:demand_array) { ["nginx", "ntp"] }
11
-
12
- it "adds a demand for each element in the array" do
13
- obj = subject.new(graph, demand_array)
14
-
15
- obj.demands.should have(2).items
16
- end
17
-
18
- context "when demand_array is an array of array" do
19
- let(:demand_array) { [["nginx", "= 1.2.3"], ["ntp", "= 1.0.0"]] }
20
-
21
- it "creates a new demand with the name and constraint of each element in the array" do
22
- obj = subject.new(graph, demand_array)
23
-
24
- obj.demands[0].name.should eql("nginx")
25
- obj.demands[0].constraint.to_s.should eql("= 1.2.3")
26
- obj.demands[1].name.should eql("ntp")
27
- obj.demands[1].constraint.to_s.should eql("= 1.0.0")
28
- end
29
- end
30
-
31
- context "when demand_array is an array of strings" do
32
- let(:demand_array) { ["nginx", "ntp"] }
33
-
34
- it "creates a new demand with the name and a default constraint of each element in the array" do
35
- obj = subject.new(graph, demand_array)
36
-
37
- obj.demands[0].name.should eql("nginx")
38
- obj.demands[0].constraint.to_s.should eql(">= 0.0.0")
39
- obj.demands[1].name.should eql("ntp")
40
- obj.demands[1].constraint.to_s.should eql(">= 0.0.0")
41
- end
42
- end
8
+ it "has a list of demands as ruby literals" do
9
+ solver.demands_array.should == demands
10
+ end
43
11
 
44
- context "when demand_array is a mix between an array of arrays and an array of strings" do
45
- let(:demand_array) { [["nginx", "= 1.2.3"], "ntp"] }
12
+ it "has a list of demands as model objects" do
13
+ expected = [
14
+ Solve::Demand.new(solver, "mysql"),
15
+ Solve::Demand.new(solver, "nginx")
16
+ ]
17
+ solver.demands.should == expected
18
+ end
46
19
 
47
- it "creates a new demand with the name and default constraint or constraint of each element in the array" do
48
- obj = subject.new(graph, demand_array)
20
+ it "has a graph" do
21
+ solver.graph.should == graph
22
+ end
49
23
 
50
- obj.demands[0].name.should eql("nginx")
51
- obj.demands[0].constraint.to_s.should eql("= 1.2.3")
52
- obj.demands[1].name.should eql("ntp")
53
- obj.demands[1].constraint.to_s.should eql(">= 0.0.0")
54
- end
55
- end
24
+ describe "when the constraints are solvable" do
25
+ let(:graph) do
26
+ graph = Solve::Graph.new
27
+ graph.artifact("A", "1.0.0")
28
+ graph.artifact("B", "1.0.0").depends("A")
29
+ graph
56
30
  end
57
31
 
58
- describe "::demand_key" do
59
- let(:demand) { Solve::Demand.new(double('solver'), "nginx", "= 1.2.3") }
32
+ let(:demands) { [["A"], ["B"]] }
60
33
 
61
- it "returns a symbol containing the name and constraint of the demand" do
62
- subject.demand_key(demand).should eql(:'nginx-= 1.2.3')
63
- end
34
+ it "gives the solution as a Hash" do
35
+ solver.resolve.should == {"A"=>"1.0.0", "B"=>"1.0.0"}
64
36
  end
65
37
 
66
- describe "::satisfy_all" do
67
- let(:ver_one) { Solve::Version.new("3.1.1") }
68
- let(:ver_two) { Solve::Version.new("3.1.2") }
69
-
70
- let(:constraints) do
71
- [
72
- Solve::Constraint.new("> 3.0.0"),
73
- Solve::Constraint.new("<= 3.1.2")
74
- ]
75
- end
76
-
77
- let(:versions) do
78
- [
79
- Solve::Version.new("0.0.1"),
80
- Solve::Version.new("0.1.0"),
81
- Solve::Version.new("1.0.0"),
82
- Solve::Version.new("2.0.0"),
83
- Solve::Version.new("3.0.0"),
84
- ver_one,
85
- ver_two,
86
- Solve::Version.new("4.1.0")
87
- ].shuffle
88
- end
89
-
90
- it "returns all of the versions which satisfy all of the given constraints" do
91
- solution = subject.satisfy_all(constraints, versions)
92
-
93
- solution.should have(2).items
94
- solution.should include(ver_one)
95
- solution.should include(ver_two)
96
- end
97
-
98
- context "given multiple duplicate versions" do
99
- let(:versions) do
100
- [
101
- ver_one,
102
- ver_one,
103
- ver_one
104
- ]
105
- end
106
-
107
- it "does not return duplicate satisfied versions" do
108
- solution = subject.satisfy_all(constraints, versions)
109
-
110
- solution.should have(1).item
111
- end
112
- end
38
+ it "gives the solution in sorted form" do
39
+ solver.resolve(sorted: true).should == [["A", "1.0.0"], ["B", "1.0.0"]]
113
40
  end
41
+ end
114
42
 
115
- describe "::satisfy_best" do
116
- let(:versions) do
117
- [
118
- Solve::Version.new("0.0.1"),
119
- Solve::Version.new("0.1.0"),
120
- Solve::Version.new("1.0.0"),
121
- Solve::Version.new("2.0.0"),
122
- Solve::Version.new("3.0.0"),
123
- Solve::Version.new("3.1.1"),
124
- Solve::Version.new("3.1.2"),
125
- Solve::Version.new("4.1.0")
126
- ].shuffle
43
+ describe "when the constraints are not solvable" do
44
+ let(:error) do
45
+ begin
46
+ solver.resolve
47
+ rescue => e
48
+ e
49
+ else
50
+ raise "Expected resolve to cause an error"
127
51
  end
52
+ end
128
53
 
129
- it "returns the best possible match for the given constraints" do
130
- subject.satisfy_best([">= 1.0.0", "< 4.1.0"], versions).to_s.should eql("3.1.2")
54
+ context "and dep-selector identifies missing artifacts" do
55
+ let(:graph) do
56
+ graph = Solve::Graph.new
57
+ graph.artifact("A", "1.0.0")
58
+ graph
131
59
  end
132
60
 
133
- context "given no version matches a constraint" do
134
- let(:versions) do
135
- [
136
- Solve::Version.new("4.1.0")
137
- ]
138
- end
61
+ let(:demands) { [ ["Z"] ] }
139
62
 
140
- it "raises a NoSolutionError error" do
141
- lambda {
142
- subject.satisfy_best(">= 5.0.0", versions)
143
- }.should raise_error(Solve::Errors::NoSolutionError)
144
- end
63
+ it "raises an error detailing the missing artifacts" do
64
+ error.to_s.should include("Missing artifacts: Z")
145
65
  end
146
66
  end
147
- end
148
-
149
- subject { Solve::Solver.new(graph) }
150
-
151
- describe "#resolve" do
152
- let(:graph) { Solve::Graph.new }
153
-
154
- subject { Solve::Solver.new(graph) }
155
-
156
- before(:each) do
157
- graph.artifacts("nginx", "1.0.0")
158
- subject.demands("nginx", "= 1.0.0")
159
- end
160
-
161
- it "returns a solution in the form of a Hash" do
162
- subject.resolve.should be_a(Hash)
163
- end
164
- end
165
-
166
- describe "#demands" do
167
- context "given a name and constraint argument" do
168
- let(:name) { "nginx" }
169
- let(:constraint) { "~> 0.101.5" }
170
-
171
- context "given the artifact of the given name and constraint does not exist" do
172
- it "returns a Solve::Demand" do
173
- subject.demands(name, constraint).should be_a(Solve::Demand)
174
- end
175
-
176
- it "the artifact has the given name" do
177
- subject.demands(name, constraint).name.should eql(name)
178
- end
179
-
180
- it "the artifact has the given constraint" do
181
- subject.demands(name, constraint).constraint.to_s.should eql(constraint)
182
- end
183
67
 
184
- it "adds an artifact to the demands collection" do
185
- subject.demands(name, constraint)
186
-
187
- subject.demands.should have(1).item
188
- end
189
-
190
- it "the artifact added matches the given name" do
191
- subject.demands(name, constraint)
192
-
193
- subject.demands[0].name.should eql(name)
194
- end
195
-
196
- it "the artifact added matches the given constraint" do
197
- subject.demands(name, constraint)
198
-
199
- subject.demands[0].constraint.to_s.should eql(constraint)
200
- end
68
+ context "and dep-selector identifies constraints that exclude all known versions" do
69
+ let(:graph) do
70
+ graph = Solve::Graph.new
71
+ graph.artifact("A", "1.0.0")
72
+ graph
201
73
  end
202
- end
203
74
 
204
- context "given only a name argument" do
205
- it "returns a demand with a match all version constraint (>= 0.0.0)" do
206
- subject.demands("nginx").constraint.to_s.should eql(">= 0.0.0")
207
- end
208
- end
75
+ let(:demands) { [ ["A", "> 1.0.0"] ] }
209
76
 
210
- context "given no arguments" do
211
- it "returns an array" do
212
- subject.demands.should be_a(Array)
77
+ it "raises an error detailing the missing artifacts" do
78
+ error.to_s.should include("Required artifacts do not exist at the desired version")
79
+ error.to_s.should include("Constraints that match no available version: (A > 1.0.0)")
213
80
  end
81
+ end
214
82
 
215
- it "returns an empty array if no demands have been accessed" do
216
- subject.demands.should have(0).items
83
+ context "and dep-selector identifies dependency conflicts" do
84
+ let(:graph) do
85
+ graph = Solve::Graph.new
86
+ graph.artifact("A", "1.0.0").depends("B").depends("C")
87
+ graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
88
+ graph.artifact("C", "1.0.0").depends("D", "= 2.0.0")
89
+ graph.artifact("D", "1.0.0")
90
+ graph.artifact("D", "2.0.0")
91
+ graph
217
92
  end
218
93
 
219
- it "returns an array containing a demand if one was accessed" do
220
- subject.demands("nginx", "~> 0.101.5")
94
+ let(:demands) { [ [ "A" ] ] }
221
95
 
222
- subject.demands.should have(1).item
96
+ it "raises an error detailing the missing artifacts" do
97
+ error.to_s.should include("Demand that cannot be met: (A >= 0.0.0)")
98
+ error.to_s.should include("Artifacts for which there are conflicting dependencies: D = 1.0.0 -> []")
223
99
  end
224
100
  end
225
101
 
226
- context "given an unexpected number of arguments" do
227
- it "raises an ArgumentError if more than two are provided" do
228
- lambda {
229
- subject.demands(1, 2, 3)
230
- }.should raise_error(ArgumentError, "Unexpected number of arguments. You gave: 3. Expected: 2 or less.")
231
- end
102
+ context "and dep-selector times out looking for a solution" do
103
+ let(:selector) { double(DepSelector::Selector) }
232
104
 
233
- it "raises an ArgumentError if a name argument of nil is provided" do
234
- lambda {
235
- subject.demands(nil)
236
- }.should raise_error(ArgumentError, "A name must be specified. You gave: [nil].")
105
+ before do
106
+ graph.stub(:artifacts).and_return([])
107
+ DepSelector::Selector.stub(:new).and_return(selector)
108
+ selector.stub(:find_solution).and_raise(DepSelector::Exceptions::TimeBoundExceeded)
237
109
  end
238
110
 
239
- it "raises an ArgumentError if a name and constraint argument are provided but name is nil" do
240
- lambda {
241
- subject.demands(nil, "= 1.0.0")
242
- }.should raise_error(ArgumentError, 'A name must be specified. You gave: [nil, "= 1.0.0"].')
111
+ it "raises an error explaining no solution could be found" do
112
+ error.to_s.should include("The dependency constraints could not be solved in the time allotted.")
243
113
  end
244
114
  end
245
- end
246
115
 
247
- describe "#add_demand" do
248
- let(:demand) { Solve::Demand.new(double('graph'), 'ntp') }
116
+ context "and dep-selector times out looking for dependency conflicts" do
117
+ let(:selector) { double(DepSelector::Selector) }
249
118
 
250
- it "adds a Solve::Artifact to the collection of artifacts" do
251
- subject.add_demand(demand)
252
-
253
- subject.should have_demand(demand)
254
- subject.demands.should have(1).item
255
- end
256
-
257
- it "should not add the same demand twice to the collection" do
258
- subject.add_demand(demand)
259
- subject.add_demand(demand)
260
-
261
- subject.demands.should have(1).item
262
- end
263
- end
264
-
265
- describe "#remove_demand" do
266
- let(:demand) { Solve::Demand.new(double('graph'), 'ntp') }
267
-
268
- context "given the demand is a member of the collection" do
269
- before(:each) { subject.add_demand(demand) }
270
-
271
- it "removes the Solve::Artifact from the collection of demands" do
272
- subject.remove_demand(demand)
273
-
274
- subject.demands.should have(0).items
119
+ before do
120
+ graph.stub(:artifacts).and_return([])
121
+ DepSelector::Selector.stub(:new).and_return(selector)
122
+ selector.stub(:find_solution).and_raise(DepSelector::Exceptions::TimeBoundExceededNoSolution)
275
123
  end
276
124
 
277
- it "returns the removed Solve::Artifact" do
278
- subject.remove_demand(demand).should eql(demand)
125
+ it "raises a NoSolutionCauseUnknown error to indicate that no debug info was generated" do
126
+ error.should be_a_kind_of(Solve::Errors::NoSolutionCauseUnknown)
279
127
  end
280
- end
281
128
 
282
- context "given the demand is not a member of the collection" do
283
- it "should return nil" do
284
- subject.remove_demand(demand).should be_nil
129
+ it "raises an error explaining that no solution exists but the cause could not be determined" do
130
+ error.to_s.should include("There is a dependency conflict, but the solver could not determine the precise cause in the time allotted.")
285
131
  end
286
132
  end
287
133
  end
288
134
 
289
- describe "#has_demand?" do
290
- let(:demand) { Solve::Demand.new(double('graph'), 'ntp') }
135
+ describe "finding unsatisfiable demands" do
136
+ it "partitions demands into satisfiable and not satisfiable"
137
+ end
291
138
 
292
- it "returns true if the given Solve::Artifact is a member of the collection" do
293
- subject.add_demand(demand)
139
+ describe "supporting Serializer interface" do
140
+ let(:serializer) { Solve::Solver::Serializer.new }
294
141
 
295
- subject.has_demand?(demand).should be_true
142
+ before do
143
+ graph.stub(:artifacts).and_return([])
296
144
  end
297
145
 
298
- it "returns false if the given Solve::Artifact is not a member of the collection" do
299
- subject.has_demand?(demand).should be_false
146
+ it "implements the required interface" do
147
+ json_string = serializer.serialize(solver)
148
+ problem_data = JSON.parse(json_string)
149
+ expected_demands = [
150
+ {"name" => "mysql", "constraint" => ">= 0.0.0"},
151
+ {"name" => "nginx", "constraint" => ">= 0.0.0"}
152
+ ]
153
+
154
+ problem_data["demands"].should =~ expected_demands
300
155
  end
301
156
  end
302
157
  end
158
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Winsor
@@ -10,8 +10,36 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-11-29 00:00:00.000000000 Z
14
- dependencies: []
13
+ date: 2014-04-07 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: semverse
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.1'
29
+ - !ruby/object:Gem::Dependency
30
+ name: dep_selector
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: 1.0.0.alpha
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: 1.0.0.alpha
15
43
  description: A Ruby version constraint solver
16
44
  email:
17
45
  - jamie@vialstudios.com
@@ -21,9 +49,8 @@ executables: []
21
49
  extensions: []
22
50
  extra_rdoc_files: []
23
51
  files:
24
- - .gitignore
25
- - .ruby-version
26
- - .travis.yml
52
+ - ".gitignore"
53
+ - ".travis.yml"
27
54
  - Gemfile
28
55
  - Guardfile
29
56
  - LICENSE
@@ -38,26 +65,19 @@ files:
38
65
  - lib/solve/gem_version.rb
39
66
  - lib/solve/graph.rb
40
67
  - lib/solve/solver.rb
41
- - lib/solve/solver/constraint_row.rb
42
- - lib/solve/solver/constraint_table.rb
43
68
  - lib/solve/solver/serializer.rb
44
- - lib/solve/solver/variable_row.rb
45
- - lib/solve/solver/variable_table.rb
46
- - lib/solve/tracers.rb
47
- - lib/solve/tracers/human_readable.rb
48
- - lib/solve/tracers/silent.rb
49
- - lib/solve/version.rb
50
69
  - solve.gemspec
70
+ - spec/acceptance/benchmark.rb
71
+ - spec/acceptance/large_graph_no_solution.rb
72
+ - spec/acceptance/opscode_ci_graph.rb
51
73
  - spec/acceptance/solutions_spec.rb
52
74
  - spec/spec_helper.rb
53
75
  - spec/unit/solve/artifact_spec.rb
54
- - spec/unit/solve/constraint_spec.rb
55
76
  - spec/unit/solve/demand_spec.rb
56
77
  - spec/unit/solve/dependency_spec.rb
57
78
  - spec/unit/solve/graph_spec.rb
58
79
  - spec/unit/solve/solver/serializer_spec.rb
59
80
  - spec/unit/solve/solver_spec.rb
60
- - spec/unit/solve/version_spec.rb
61
81
  - spec/unit/solve_spec.rb
62
82
  homepage: https://github.com/berkshelf/solve
63
83
  licenses:
@@ -69,30 +89,31 @@ require_paths:
69
89
  - lib
70
90
  required_ruby_version: !ruby/object:Gem::Requirement
71
91
  requirements:
72
- - - '>='
92
+ - - ">="
73
93
  - !ruby/object:Gem::Version
74
94
  version: 1.9.1
75
95
  required_rubygems_version: !ruby/object:Gem::Requirement
76
96
  requirements:
77
- - - '>='
97
+ - - ">"
78
98
  - !ruby/object:Gem::Version
79
- version: '0'
99
+ version: 1.3.1
80
100
  requirements: []
81
101
  rubyforge_project:
82
- rubygems_version: 2.0.7
102
+ rubygems_version: 2.2.2
83
103
  signing_key:
84
104
  specification_version: 4
85
105
  summary: A Ruby version constraint solver implementing Semantic Versioning 2.0.0-rc.1
86
106
  test_files:
107
+ - spec/acceptance/benchmark.rb
108
+ - spec/acceptance/large_graph_no_solution.rb
109
+ - spec/acceptance/opscode_ci_graph.rb
87
110
  - spec/acceptance/solutions_spec.rb
88
111
  - spec/spec_helper.rb
89
112
  - spec/unit/solve/artifact_spec.rb
90
- - spec/unit/solve/constraint_spec.rb
91
113
  - spec/unit/solve/demand_spec.rb
92
114
  - spec/unit/solve/dependency_spec.rb
93
115
  - spec/unit/solve/graph_spec.rb
94
116
  - spec/unit/solve/solver/serializer_spec.rb
95
117
  - spec/unit/solve/solver_spec.rb
96
- - spec/unit/solve/version_spec.rb
97
118
  - spec/unit/solve_spec.rb
98
119
  has_rdoc: