solve 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +11 -6
- data/Gemfile +8 -8
- data/NoGecode.gemfile +4 -0
- data/README.md +16 -0
- data/Rakefile +1 -0
- data/Thorfile +5 -0
- data/lib/solve.rb +43 -2
- data/lib/solve/demand.rb +2 -2
- data/lib/solve/errors.rb +6 -0
- data/lib/solve/{solver.rb → gecode_solver.rb} +12 -4
- data/lib/solve/ruby_solver.rb +207 -0
- data/lib/solve/solver/serializer.rb +37 -15
- data/lib/solve/version.rb +1 -1
- data/solve.gemspec +7 -1
- data/spec/acceptance/benchmark.rb +17 -3
- data/spec/acceptance/ruby_solver_solutions_spec.rb +307 -0
- data/spec/acceptance/solutions_spec.rb +6 -1
- data/spec/unit/solve/{solver_spec.rb → gecode_solver_spec.rb} +34 -4
- data/spec/unit/solve/ruby_solver_spec.rb +166 -0
- data/spec/unit/solve/solver/serializer_spec.rb +22 -14
- data/spec/unit/solve_spec.rb +2 -2
- metadata +71 -8
@@ -1,12 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
require 'solve/gecode_solver'
|
4
|
+
|
5
|
+
describe Solve::GecodeSolver, :gecode do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
described_class.activate
|
9
|
+
end
|
10
|
+
|
4
11
|
describe "ClassMethods" do
|
5
12
|
describe "::timeout" do
|
6
13
|
subject { described_class.timeout }
|
7
14
|
|
8
|
-
it "returns
|
9
|
-
expect(subject).to eql(
|
15
|
+
it "returns 30,000 by default" do
|
16
|
+
expect(subject).to eql(30_000)
|
10
17
|
end
|
11
18
|
|
12
19
|
context "when the SOLVE_TIMEOUT env variable is set" do
|
@@ -17,6 +24,28 @@ describe Solve::Solver do
|
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
27
|
+
|
28
|
+
describe "::activate" do
|
29
|
+
|
30
|
+
context "when dep_selector is not installed" do
|
31
|
+
|
32
|
+
it "raises EngineNotAvailable" do
|
33
|
+
exception = LoadError.new("cannot load such file -- dep_selector")
|
34
|
+
allow(described_class).to receive(:require).with("dep_selector").and_raise(exception)
|
35
|
+
expect { described_class.activate }.to raise_error(Solve::Errors::EngineNotAvailable)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when dep_selector is installed" do
|
41
|
+
|
42
|
+
it "requires dep_selector" do
|
43
|
+
expect(described_class).to receive(:require).with("dep_selector").and_call_original
|
44
|
+
described_class.activate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
20
49
|
end
|
21
50
|
|
22
51
|
let(:graph) { double(Solve::Graph) }
|
@@ -162,7 +191,8 @@ describe Solve::Solver do
|
|
162
191
|
end
|
163
192
|
|
164
193
|
it "implements the required interface" do
|
165
|
-
|
194
|
+
problem = Solve::Problem.from_solver(solver)
|
195
|
+
json_string = serializer.serialize(problem)
|
166
196
|
problem_data = JSON.parse(json_string)
|
167
197
|
expected_demands = [
|
168
198
|
{"name" => "mysql", "constraint" => ">= 0.0.0"},
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Solve::RubySolver do
|
4
|
+
describe "ClassMethods" do
|
5
|
+
describe "::timeout" do
|
6
|
+
subject { described_class.timeout }
|
7
|
+
|
8
|
+
it "returns 30,000 by default" do
|
9
|
+
expect(subject).to eql(30_000)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when the SOLVE_TIMEOUT env variable is set" do
|
13
|
+
before { ENV.stub(:[]).with("SOLVE_TIMEOUT") { "30" } }
|
14
|
+
|
15
|
+
it "returns the value multiplied by a thousand" do
|
16
|
+
expect(subject).to eql(30_000)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "::activate" do
|
22
|
+
|
23
|
+
it "is a no-op" do
|
24
|
+
described_class.activate
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:graph) { double(Solve::Graph) }
|
31
|
+
let(:demands) { [["mysql"], ["nginx"]] }
|
32
|
+
subject(:solver) { described_class.new(graph, demands, dependency_source: "Berksfile") }
|
33
|
+
|
34
|
+
it "has a list of demands as ruby literals" do
|
35
|
+
solver.demands_array.should == demands
|
36
|
+
end
|
37
|
+
|
38
|
+
it "has a list of demands as model objects" do
|
39
|
+
expected = [
|
40
|
+
Solve::Demand.new(solver, "mysql"),
|
41
|
+
Solve::Demand.new(solver, "nginx")
|
42
|
+
]
|
43
|
+
solver.demands.should == expected
|
44
|
+
end
|
45
|
+
|
46
|
+
it "has a graph" do
|
47
|
+
solver.graph.should == graph
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when the constraints are solvable" do
|
51
|
+
let(:graph) do
|
52
|
+
graph = Solve::Graph.new
|
53
|
+
graph.artifact("A", "1.0.0")
|
54
|
+
graph.artifact("B", "1.0.0").depends("A")
|
55
|
+
graph
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:demands) { [["A"], ["B"]] }
|
59
|
+
|
60
|
+
it "gives the solution as a Hash" do
|
61
|
+
solver.resolve.should == {"A"=>"1.0.0", "B"=>"1.0.0"}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "gives the solution in sorted form" do
|
65
|
+
solver.resolve(sorted: true).should == [["A", "1.0.0"], ["B", "1.0.0"]]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "when the constraints are not solvable" do
|
70
|
+
let(:error) do
|
71
|
+
begin
|
72
|
+
solver.resolve
|
73
|
+
rescue => e
|
74
|
+
e
|
75
|
+
else
|
76
|
+
raise "Expected resolve to cause an error"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "and molinillo identifies missing artifacts" do
|
81
|
+
let(:graph) do
|
82
|
+
graph = Solve::Graph.new
|
83
|
+
graph.artifact("A", "1.0.0")
|
84
|
+
graph
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:demands) { [ ["Z"] ] }
|
88
|
+
|
89
|
+
it "raises an error detailing the missing artifacts" do
|
90
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
91
|
+
expected_error = <<-ERROR_MESSAGE
|
92
|
+
Unable to satisfy the following requirements:
|
93
|
+
|
94
|
+
- `Z (>= 0.0.0)` required by `Berksfile`
|
95
|
+
ERROR_MESSAGE
|
96
|
+
expect(error.to_s).to eq(expected_error)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "and molinillo identifies constraints that exclude all known versions" do
|
101
|
+
let(:graph) do
|
102
|
+
graph = Solve::Graph.new
|
103
|
+
graph.artifact("A", "1.0.0")
|
104
|
+
graph
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:demands) { [ ["A", "> 1.0.0"] ] }
|
108
|
+
|
109
|
+
it "raises an error detailing the missing artifacts" do
|
110
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
111
|
+
expected_error = <<-ERROR_MESSAGE
|
112
|
+
Unable to satisfy the following requirements:
|
113
|
+
|
114
|
+
- `A (> 1.0.0)` required by `Berksfile`
|
115
|
+
ERROR_MESSAGE
|
116
|
+
expect(error.to_s).to eq(expected_error)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "and molinillo identifies dependency conflicts" do
|
121
|
+
let(:graph) do
|
122
|
+
graph = Solve::Graph.new
|
123
|
+
graph.artifact("A", "1.0.0").depends("B").depends("C")
|
124
|
+
graph.artifact("B", "1.0.0").depends("D", "= 1.0.0")
|
125
|
+
graph.artifact("C", "1.0.0").depends("D", "= 2.0.0")
|
126
|
+
graph.artifact("D", "1.0.0")
|
127
|
+
graph.artifact("D", "2.0.0")
|
128
|
+
graph
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:demands) { [ [ "A" ] ] }
|
132
|
+
|
133
|
+
it "raises an error detailing the missing artifacts" do
|
134
|
+
expect(error).to be_a_kind_of(Solve::Errors::NoSolutionError)
|
135
|
+
expected_error = <<-ERROR_MESSAGE
|
136
|
+
Unable to satisfy the following requirements:
|
137
|
+
|
138
|
+
- `D (= 1.0.0)` required by `B-1.0.0`
|
139
|
+
- `D (= 2.0.0)` required by `C-1.0.0`
|
140
|
+
ERROR_MESSAGE
|
141
|
+
expect(error.to_s).to eq(expected_error)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "supporting Serializer interface" do
|
147
|
+
let(:serializer) { Solve::Solver::Serializer.new }
|
148
|
+
|
149
|
+
before do
|
150
|
+
graph.stub(:artifacts).and_return([])
|
151
|
+
end
|
152
|
+
|
153
|
+
it "implements the required interface" do
|
154
|
+
problem = Solve::Problem.from_solver(solver)
|
155
|
+
json_string = serializer.serialize(problem)
|
156
|
+
problem_data = JSON.parse(json_string)
|
157
|
+
expected_demands = [
|
158
|
+
{"name" => "mysql", "constraint" => ">= 0.0.0"},
|
159
|
+
{"name" => "nginx", "constraint" => ">= 0.0.0"}
|
160
|
+
]
|
161
|
+
|
162
|
+
problem_data["demands"].should =~ expected_demands
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
@@ -1,25 +1,33 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'solve/ruby_solver'
|
2
3
|
|
3
4
|
describe Solve::Solver::Serializer do
|
4
|
-
it "deserializes a serialized solver to an equivalent solver" do
|
5
|
-
graph = Solve::Graph.new
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
let(:graph) do
|
7
|
+
Solve::Graph.new.tap do |g|
|
8
|
+
g.artifact("A", "1.0.0").depends("B", "1.0.0")
|
9
|
+
g.artifact("B", "1.0.0").depends("C", "1.0.0")
|
10
|
+
g.artifact("C", "1.0.0")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:demands) { [["A", "1.0.0"]] }
|
10
15
|
|
11
|
-
|
16
|
+
let(:serializer) { Solve::Solver::Serializer.new }
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
serialized = serializer.serialize(
|
18
|
+
it "deserializes a serialized problem to an equivalent problem" do
|
19
|
+
problem = Solve::Problem.new(graph, demands)
|
20
|
+
serialized = serializer.serialize(problem)
|
16
21
|
deserialized = serializer.deserialize(serialized)
|
17
22
|
|
18
|
-
|
19
|
-
|
23
|
+
problem.graph.should eql(deserialized.graph)
|
24
|
+
problem.demands.should eql(deserialized.demands)
|
25
|
+
end
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
27
|
+
it "creates a problem from a solver" do
|
28
|
+
solver = Solve::RubySolver.new(graph, demands)
|
29
|
+
problem = Solve::Problem.from_solver(solver)
|
30
|
+
expect(problem.demands).to eq([["A", "= 1.0.0"]])
|
31
|
+
expect(problem.graph).to eq(graph)
|
24
32
|
end
|
25
33
|
end
|
data/spec/unit/solve_spec.rb
CHANGED
@@ -6,13 +6,13 @@ describe Solve do
|
|
6
6
|
|
7
7
|
describe "#it" do
|
8
8
|
it "returns nil if a solution does not exist" do
|
9
|
-
|
9
|
+
skip
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
describe "#it!" do
|
14
14
|
it "raises NoSolutionError if a solution does not exist" do
|
15
|
-
|
15
|
+
skip
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
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:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Winsor
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: semverse
|
@@ -27,19 +27,75 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '1.1'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
30
|
+
name: molinillo
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: 0.2.3
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 0.2.3
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: thor
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.16.0
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.16.0
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rake
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.9.2.2
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.9.2.2
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: spork
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: rspec
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '3.0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '3.0'
|
43
99
|
description: A Ruby version constraint solver
|
44
100
|
email:
|
45
101
|
- jamie@vialstudios.com
|
@@ -54,7 +110,9 @@ files:
|
|
54
110
|
- Gemfile
|
55
111
|
- Guardfile
|
56
112
|
- LICENSE
|
113
|
+
- NoGecode.gemfile
|
57
114
|
- README.md
|
115
|
+
- Rakefile
|
58
116
|
- Thorfile
|
59
117
|
- lib/solve.rb
|
60
118
|
- lib/solve/artifact.rb
|
@@ -62,22 +120,25 @@ files:
|
|
62
120
|
- lib/solve/demand.rb
|
63
121
|
- lib/solve/dependency.rb
|
64
122
|
- lib/solve/errors.rb
|
123
|
+
- lib/solve/gecode_solver.rb
|
65
124
|
- lib/solve/graph.rb
|
66
|
-
- lib/solve/
|
125
|
+
- lib/solve/ruby_solver.rb
|
67
126
|
- lib/solve/solver/serializer.rb
|
68
127
|
- lib/solve/version.rb
|
69
128
|
- solve.gemspec
|
70
129
|
- spec/acceptance/benchmark.rb
|
71
130
|
- spec/acceptance/large_graph_no_solution.rb
|
72
131
|
- spec/acceptance/opscode_ci_graph.rb
|
132
|
+
- spec/acceptance/ruby_solver_solutions_spec.rb
|
73
133
|
- spec/acceptance/solutions_spec.rb
|
74
134
|
- spec/spec_helper.rb
|
75
135
|
- spec/unit/solve/artifact_spec.rb
|
76
136
|
- spec/unit/solve/demand_spec.rb
|
77
137
|
- spec/unit/solve/dependency_spec.rb
|
138
|
+
- spec/unit/solve/gecode_solver_spec.rb
|
78
139
|
- spec/unit/solve/graph_spec.rb
|
140
|
+
- spec/unit/solve/ruby_solver_spec.rb
|
79
141
|
- spec/unit/solve/solver/serializer_spec.rb
|
80
|
-
- spec/unit/solve/solver_spec.rb
|
81
142
|
- spec/unit/solve_spec.rb
|
82
143
|
homepage: https://github.com/berkshelf/solve
|
83
144
|
licenses:
|
@@ -107,13 +168,15 @@ test_files:
|
|
107
168
|
- spec/acceptance/benchmark.rb
|
108
169
|
- spec/acceptance/large_graph_no_solution.rb
|
109
170
|
- spec/acceptance/opscode_ci_graph.rb
|
171
|
+
- spec/acceptance/ruby_solver_solutions_spec.rb
|
110
172
|
- spec/acceptance/solutions_spec.rb
|
111
173
|
- spec/spec_helper.rb
|
112
174
|
- spec/unit/solve/artifact_spec.rb
|
113
175
|
- spec/unit/solve/demand_spec.rb
|
114
176
|
- spec/unit/solve/dependency_spec.rb
|
177
|
+
- spec/unit/solve/gecode_solver_spec.rb
|
115
178
|
- spec/unit/solve/graph_spec.rb
|
179
|
+
- spec/unit/solve/ruby_solver_spec.rb
|
116
180
|
- spec/unit/solve/solver/serializer_spec.rb
|
117
|
-
- spec/unit/solve/solver_spec.rb
|
118
181
|
- spec/unit/solve_spec.rb
|
119
182
|
has_rdoc:
|