doubleshot 0.2.0-java → 0.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Doubleshot +16 -6
  2. data/README-OLD.textile +216 -0
  3. data/README.textile +38 -182
  4. data/lib/doubleshot.rb +100 -39
  5. data/lib/doubleshot/commands/gem.rb +15 -12
  6. data/lib/doubleshot/commands/test.rb +38 -5
  7. data/lib/doubleshot/configuration.rb +2 -2
  8. data/lib/doubleshot/dependencies/dependency.rb +1 -1
  9. data/lib/doubleshot/dependencies/gem_dependency.rb +2 -10
  10. data/lib/doubleshot/dependencies/jar_dependency.rb +12 -2
  11. data/lib/doubleshot/lockfile.rb +9 -6
  12. data/lib/doubleshot/pom.rb +15 -2
  13. data/lib/doubleshot/resolver.rb +1 -0
  14. data/lib/doubleshot/resolver/gem_resolver.rb +45 -0
  15. data/lib/doubleshot/resolver/gem_resolver/artifact.rb +146 -0
  16. data/lib/doubleshot/resolver/gem_resolver/demand.rb +57 -0
  17. data/lib/doubleshot/resolver/gem_resolver/dependency.rb +57 -0
  18. data/lib/doubleshot/resolver/gem_resolver/errors.rb +37 -0
  19. data/lib/doubleshot/resolver/gem_resolver/gem_source.rb +58 -0
  20. data/lib/doubleshot/resolver/gem_resolver/graph.rb +200 -0
  21. data/lib/doubleshot/resolver/gem_resolver/solver.rb +279 -0
  22. data/lib/doubleshot/resolver/gem_resolver/solver/constraint_row.rb +29 -0
  23. data/lib/doubleshot/resolver/gem_resolver/solver/constraint_table.rb +35 -0
  24. data/lib/doubleshot/resolver/gem_resolver/solver/variable_row.rb +47 -0
  25. data/lib/doubleshot/resolver/gem_resolver/solver/variable_table.rb +59 -0
  26. data/lib/doubleshot/resolver/gem_resolver/source.rb +36 -0
  27. data/lib/doubleshot/resolver/jar_resolver.rb +1 -3
  28. data/lib/ruby/gem/requirement.rb +9 -0
  29. data/target/doubleshot.jar +0 -0
  30. data/test/compiler_spec.rb +31 -3
  31. data/test/configuration_spec.rb +11 -3
  32. data/test/dependencies/gem_dependency_spec.rb +3 -17
  33. data/test/dependencies/jar_dependency_spec.rb +20 -0
  34. data/test/helper.rb +3 -1
  35. data/test/helpers/stub_source.rb +120 -0
  36. data/test/lockfile_spec.rb +9 -17
  37. data/test/pom_spec.rb +31 -1
  38. data/test/resolver/gem_resolver/artifact_spec.rb +106 -0
  39. data/test/resolver/gem_resolver/demand_spec.rb +70 -0
  40. data/test/resolver/gem_resolver/dependency_spec.rb +33 -0
  41. data/test/resolver/gem_resolver/gem_source_spec.rb +28 -0
  42. data/test/resolver/gem_resolver/graph_spec.rb +239 -0
  43. data/test/resolver/gem_resolver/solver_spec.rb +449 -0
  44. data/test/resolver/gem_resolver/source_spec.rb +18 -0
  45. data/test/resolver/gem_resolver_spec.rb +102 -0
  46. metadata +35 -73
  47. data/lib/doubleshot/jar.rb +0 -62
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ # encoding: utf-8
4
+
5
+ require_relative "../../helper"
6
+
7
+ describe Doubleshot::Resolver::GemResolver::Demand do
8
+ before do
9
+ @solver = MiniTest::Mock.new
10
+ end
11
+
12
+ describe "ClassMethods" do
13
+ describe "::new" do
14
+ it "accepts a string for the constraint parameter" do
15
+ Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen", "= 0.0.1")
16
+ .constraint.to_s.must_equal "= 0.0.1"
17
+ end
18
+
19
+ it "accepts a Gem::Requirement for the constraint parameter" do
20
+ constraint = Gem::Requirement.new("= 0.0.1")
21
+
22
+ Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen", constraint)
23
+ .constraint.must_equal constraint
24
+ end
25
+
26
+ describe "when no value for 'constraint' is given" do
27
+ it "uses a default of >= 0" do
28
+ Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen")
29
+ .constraint.to_s.must_equal ">= 0"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "#delete" do
36
+ describe "given the demand is not the member of a solver" do
37
+ it "returns nil" do
38
+ Doubleshot::Resolver::GemResolver::Demand.new(nil, "listen", "~> 1.0.0")
39
+ .delete.must_be_nil
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "equality" do
45
+ before do
46
+ @demand = Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen", "1.0")
47
+ end
48
+
49
+ it "returns true when other is a Doubleshot::Resolver::GemResolver::Demand with the same name and constriant" do
50
+ other_demand = Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen", "1.0")
51
+ @demand.must_equal other_demand
52
+ end
53
+
54
+ it "returns false when other isn't a Solve::Demand" do
55
+ @demand.wont_equal "chicken"
56
+ end
57
+
58
+ it "returns false when other is a Solve::Demand with the same name but a different constraint" do
59
+ other_demand = Doubleshot::Resolver::GemResolver::Demand.new(@solver, "listen", "< 3.4.5")
60
+
61
+ @demand.wont_equal other_demand
62
+ end
63
+
64
+ it "returns false when other is a Solve::Demand with the same constraint but a different name" do
65
+ other_demand = Doubleshot::Resolver::GemResolver::Demand.new(@solver, "chicken", "1.0")
66
+
67
+ @demand.wont_equal other_demand
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ # encoding: utf-8
4
+
5
+ require_relative "../../helper"
6
+
7
+ describe Doubleshot::Resolver::GemResolver::Dependency do
8
+ before do
9
+ @dependency = Doubleshot::Resolver::GemResolver::Dependency.new(
10
+ Doubleshot::Resolver::GemResolver::Artifact.new(nil, "something_using_ntp", "1.0"),
11
+ "ntp")
12
+ end
13
+
14
+ describe "ClassMethods" do
15
+ describe "::new" do
16
+ describe "when no value for 'constraint' is given" do
17
+ it "uses a default of >= 0" do
18
+ @dependency.constraint.to_s.must_equal ">= 0"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#eql?" do
25
+ it "returns true if the other object is an instance of Solve::Dependency with the same constraint and artifact" do
26
+ other = Doubleshot::Resolver::GemResolver::Dependency.new(
27
+ Doubleshot::Resolver::GemResolver::Artifact.new(nil, "something_using_ntp", "1.0"),
28
+ "ntp")
29
+
30
+ @dependency.must_equal other
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ # encoding: utf-8
4
+
5
+ require_relative "../../helper"
6
+
7
+ describe Doubleshot::Resolver::GemResolver::Source do
8
+
9
+ before do
10
+ @source = Doubleshot::Resolver::GemResolver::Source.new Doubleshot::Resolver::GemResolver::DEFAULT_REPOSITORY
11
+ end
12
+
13
+ describe "versions" do
14
+ it "must return a list of available versions for a gem name" do
15
+ versions = @source.versions("rack")
16
+ versions.size.must_be :>, 10
17
+ versions.must_include Gem::Version.new "1.2.0"
18
+ end
19
+ end
20
+
21
+ describe "spec" do
22
+ it "must return a gemspec for a given gem name and version" do
23
+ gemspec = @source.spec "rack", "1.2.0"
24
+ gemspec.name.must_equal "rack"
25
+ gemspec.version.to_s.must_equal "1.2.0"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ # encoding: utf-8
4
+
5
+ require_relative "../../helper"
6
+
7
+ describe Doubleshot::Resolver::GemResolver::Graph do
8
+ before do
9
+ @graph = Doubleshot::Resolver::GemResolver::Graph.new
10
+ end
11
+
12
+ describe "ClassMethods" do
13
+ describe "::artifact_key" do
14
+ it "returns a symbol containing the name and version of the artifact" do
15
+ Doubleshot::Resolver::GemResolver::Graph::artifact_key("nginx", "1.2.3").must_equal :'nginx-1.2.3'
16
+ end
17
+ end
18
+
19
+ describe "::dependency_key" do
20
+ it "returns a symbol containing the name and constraint of the dependency" do
21
+ Doubleshot::Resolver::GemResolver::Graph::dependency_key("ntp", "= 2.3.4").must_equal :'ntp-= 2.3.4'
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "#artifacts" do
27
+ describe "given a name and version argument" do
28
+ before do
29
+ @name = "nginx"
30
+ @version = "0.101.5"
31
+ end
32
+
33
+ describe "given the artifact of the given name and version does not exist" do
34
+ it "returns a Doubleshot::Resolver::GemResolver::Artifact" do
35
+ @graph.artifacts(@name, @version).must_be_kind_of Doubleshot::Resolver::GemResolver::Artifact
36
+ end
37
+
38
+ it "the artifact has the given name" do
39
+ @graph.artifacts(@name, @version).name.must_equal @name
40
+ end
41
+
42
+ it "the artifact has the given version" do
43
+ @graph.artifacts(@name, @version).version.to_s.must_equal @version
44
+ end
45
+
46
+ it "adds an artifact to the artifacts collection" do
47
+ @graph.artifacts(@name, @version)
48
+
49
+ @graph.artifacts.size.must_equal 1
50
+ end
51
+
52
+ it "the artifact added matches the given name" do
53
+ @graph.artifacts(@name, @version)
54
+
55
+ @graph.artifacts[0].name.must_equal @name
56
+ end
57
+
58
+ it "the artifact added matches the given version" do
59
+ @graph.artifacts(@name, @version)
60
+
61
+ @graph.artifacts[0].version.to_s.must_equal @version
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "given no arguments" do
67
+ it "returns an array" do
68
+ @graph.artifacts.must_be_kind_of Array
69
+ end
70
+
71
+ it "returns an empty array if no artifacts have been accessed" do
72
+ @graph.artifacts.size.must_equal 0
73
+ end
74
+
75
+ it "returns an array containing an artifact if one was accessed" do
76
+ @graph.artifacts("nginx", "0.101.5")
77
+
78
+ @graph.artifacts.size.must_equal 1
79
+ end
80
+ end
81
+
82
+ describe "given an unexpected number of arguments" do
83
+ it "raises an ArgumentError if more than two are provided" do
84
+ -> { @graph.artifacts(1, 2, 3) }.must_raise ArgumentError, "Unexpected number of arguments. You gave: 3. Expected: 0 or 2."
85
+ end
86
+
87
+ it "raises an ArgumentError if one argument is provided" do
88
+ -> { @graph.artifacts(nil) }.must_raise ArgumentError, "Unexpected number of arguments. You gave: 1. Expected: 0 or 2."
89
+ end
90
+
91
+ it "raises an ArgumentError if one of the arguments provided is nil" do
92
+ -> { @graph.artifacts("nginx", nil) }.must_raise ArgumentError, 'A name and version must be specified. You gave: ["nginx", nil].'
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#get_artifact" do
98
+ before do
99
+ @graph.artifacts("nginx", "1.0.0")
100
+ end
101
+
102
+ it "returns an instance of artifact of the matching name and version" do
103
+ artifact = @graph.get_artifact("nginx", "1.0.0")
104
+
105
+ artifact.must_be_kind_of Doubleshot::Resolver::GemResolver::Artifact
106
+ artifact.name.must_equal "nginx"
107
+ artifact.version.to_s.must_equal "1.0.0"
108
+ end
109
+
110
+ describe "when an artifact of the given name is not in the collection of artifacts" do
111
+ it "returns nil" do
112
+ @graph.get_artifact("nothere", "1.0.0").must_be_nil
113
+ end
114
+ end
115
+ end
116
+
117
+ describe "#versions" do
118
+ before do
119
+ @graph.artifacts("nginx", "1.0.0")
120
+ @graph.artifacts("nginx", "2.0.0")
121
+ @graph.artifacts("nginx", "3.0.0")
122
+ @graph.artifacts("nginx", "4.0.0")
123
+ @graph.artifacts("nginx", "5.0.0")
124
+ @graph.artifacts("nginx", "4.0.0")
125
+ end
126
+
127
+ it "returns all the artifacts matching the given name" do
128
+ @graph.versions("nginx").size.must_equal 5
129
+ end
130
+
131
+ describe "given an optional constraint value" do
132
+ it "returns only the artifacts matching the given constraint value and name" do
133
+ @graph.versions("nginx", ">= 4.0.0").size.must_equal 2
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#add_artifact" do
139
+ before do
140
+ @artifact = Doubleshot::Resolver::GemResolver::Artifact.new(@graph, "nginx", "1.0.0")
141
+ end
142
+
143
+ it "adds a Doubleshot::Resolver::GemResolver::Artifact to the collection of artifacts" do
144
+ @graph.add_artifact @artifact
145
+
146
+ @graph.artifacts.must_include @artifact
147
+ @graph.artifacts.size.must_equal 1
148
+ end
149
+
150
+ it "should not add the same artifact twice to the collection" do
151
+ @graph.add_artifact @artifact
152
+ @graph.add_artifact @artifact
153
+
154
+ @graph.artifacts.size.must_equal 1
155
+ end
156
+ end
157
+
158
+ describe "#remove_artifact" do
159
+ before do
160
+ @artifact = Doubleshot::Resolver::GemResolver::Artifact.new(@graph, "nginx", "1.0.0")
161
+ end
162
+
163
+ describe "given the artifact is a member of the collection" do
164
+ before do
165
+ @graph.add_artifact @artifact
166
+ end
167
+
168
+ it "removes the Solve::Artifact from the collection of artifacts" do
169
+ @graph.remove_artifact(@artifact)
170
+
171
+ @graph.artifacts.size.must_equal 0
172
+ end
173
+
174
+ it "returns the removed Solve::Artifact" do
175
+ @graph.remove_artifact(@artifact).must_equal @artifact
176
+ end
177
+ end
178
+
179
+ describe "given the artifact is not a member of the collection" do
180
+ it "should return nil" do
181
+ @graph.remove_artifact(@artifact).must_be_nil
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "#has_artifact?" do
187
+ before do
188
+ @artifact = Doubleshot::Resolver::GemResolver::Artifact.new(@graph, "nginx", "1.0.0")
189
+ end
190
+
191
+ it "returns true if the given Solve::Artifact is a member of the collection" do
192
+ @graph.add_artifact @artifact
193
+
194
+ @graph.has_artifact?(@artifact.name, @artifact.version).must_equal true
195
+ end
196
+
197
+ it "returns false if the given Solve::Artifact is not a member of the collection" do
198
+ @graph.has_artifact?(@artifact.name, @artifact.version).must_equal false
199
+ end
200
+ end
201
+
202
+ describe "eql?" do
203
+ before do
204
+ @graph = Doubleshot::Resolver::GemResolver::Graph.new
205
+ @graph.artifacts("A", "1.0.0").depends("B", "1.0.0")
206
+ @graph.artifacts("A", "2.0.0").depends("C", "1.0.0")
207
+ @graph
208
+ end
209
+
210
+ it "returns false if other isn't a Solve::Graph" do
211
+ @graph.wont_equal "chicken"
212
+ end
213
+
214
+ it "returns true if other is a Solve::Graph with the same artifacts and dependencies" do
215
+ other = Doubleshot::Resolver::GemResolver::Graph.new
216
+ other.artifacts("A", "1.0.0").depends("B", "1.0.0")
217
+ other.artifacts("A", "2.0.0").depends("C", "1.0.0")
218
+
219
+ @graph.must_equal other
220
+ end
221
+
222
+ it "returns false if the other is a Solve::Graph with the same artifacts but different dependencies" do
223
+ other = Doubleshot::Resolver::GemResolver::Graph.new
224
+ other.artifacts("A", "1.0.0")
225
+ other.artifacts("A", "2.0.0")
226
+
227
+ @graph.wont_equal other
228
+ end
229
+
230
+ it "returns false if the other is a Solve::Graph with the same dependencies but different artifacts" do
231
+ other = Doubleshot::Resolver::GemResolver::Graph.new
232
+ other.artifacts("A", "1.0.0").depends("B", "1.0.0")
233
+ other.artifacts("A", "2.0.0").depends("C", "1.0.0")
234
+ other.artifacts("B", "1.0.0")
235
+
236
+ @graph.wont_equal other
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,449 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ # encoding: utf-8
4
+
5
+ require_relative "../../helper"
6
+
7
+ describe Doubleshot::Resolver::GemResolver::Solver do
8
+ before do
9
+ @graph = Doubleshot::Resolver::GemResolver::Graph.new
10
+ @solver = Doubleshot::Resolver::GemResolver::Solver.new(@graph)
11
+ end
12
+
13
+ describe "ClassMethods" do
14
+ describe "::new" do
15
+
16
+ it "adds a demand for each element in the array" do
17
+ solver = Doubleshot::Resolver::GemResolver::Solver.new(@graph, ["nginx", "ntp"])
18
+ solver.demands.size.must_equal 2
19
+ end
20
+
21
+ describe "when demand_array is an array of array" do
22
+ it "creates a new demand with the name and constraint of each element in the array" do
23
+ solver = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["nginx", "= 1.2.3"], ["ntp", "= 1.0.0"]])
24
+
25
+ solver.demands[0].name.must_equal "nginx"
26
+ solver.demands[0].constraint.to_s.must_equal "= 1.2.3"
27
+ solver.demands[1].name.must_equal "ntp"
28
+ solver.demands[1].constraint.to_s.must_equal "= 1.0.0"
29
+ end
30
+ end
31
+
32
+ describe "when demand_array is an array of strings" do
33
+ it "creates a new demand with the name and a default constraint of each element in the array" do
34
+ solver = Doubleshot::Resolver::GemResolver::Solver.new(@graph, ["nginx", "ntp"])
35
+
36
+ solver.demands[0].name.must_equal "nginx"
37
+ solver.demands[0].constraint.to_s.must_equal ">= 0"
38
+ solver.demands[1].name.must_equal "ntp"
39
+ solver.demands[1].constraint.to_s.must_equal ">= 0"
40
+ end
41
+ end
42
+
43
+ describe "when demand_array is a mix between an array of arrays and an array of strings" do
44
+ let(:demand_array) { [["nginx", "= 1.2.3"], "ntp"] }
45
+
46
+ it "creates a new demand with the name and default constraint or constraint of each element in the array" do
47
+ solver = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["nginx", "= 1.2.3"], "ntp"])
48
+
49
+ solver.demands[0].name.must_equal "nginx"
50
+ solver.demands[0].constraint.to_s.must_equal "= 1.2.3"
51
+ solver.demands[1].name.must_equal "ntp"
52
+ solver.demands[1].constraint.to_s.must_equal ">= 0"
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "::demand_key" do
58
+ it "returns a symbol containing the name and constraint of the demand" do
59
+ demand = Doubleshot::Resolver::GemResolver::Demand.new(MiniTest::Mock.new, "nginx", "= 1.2.3")
60
+ Doubleshot::Resolver::GemResolver::Solver::demand_key(demand).must_equal :'nginx-= 1.2.3'
61
+ end
62
+ end
63
+
64
+ describe "::satisfy_all" do
65
+ before do
66
+ @version_1 = Gem::Version.new("3.1.1")
67
+ @version_2 = Gem::Version.new("3.1.2")
68
+
69
+ @constraints = [
70
+ Gem::Requirement.new("> 3.0.0"),
71
+ Gem::Requirement.new("<= 3.1.2")
72
+ ]
73
+
74
+ @versions = [
75
+ Gem::Version.new("0.0.1"),
76
+ Gem::Version.new("0.1.0"),
77
+ Gem::Version.new("1.0.0"),
78
+ Gem::Version.new("2.0.0"),
79
+ Gem::Version.new("3.0.0"),
80
+ @version_1,
81
+ @version_2,
82
+ Gem::Version.new("4.1.0")
83
+ ].shuffle
84
+ end
85
+
86
+ it "returns all of the versions which satisfy all of the given constraints" do
87
+ solution = Doubleshot::Resolver::GemResolver::Solver::satisfy_all(@constraints, @versions)
88
+
89
+ solution.size.must_equal 2
90
+ solution.must_include @version_1
91
+ solution.must_include @version_2
92
+ end
93
+
94
+ it "does not return duplicate satisfied versions given multiple duplicate versions" do
95
+ solution = Doubleshot::Resolver::GemResolver::Solver::satisfy_all(@constraints, [@version_1, @version_1, @version_1])
96
+
97
+ solution.size.must_equal 1
98
+ solution.must_include @version_1
99
+ end
100
+ end
101
+
102
+ describe "::satisfy_best" do
103
+ before do
104
+ @versions = [
105
+ Gem::Version.new("0.0.1"),
106
+ Gem::Version.new("0.1.0"),
107
+ Gem::Version.new("1.0.0"),
108
+ Gem::Version.new("2.0.0"),
109
+ Gem::Version.new("3.0.0"),
110
+ Gem::Version.new("3.1.1"),
111
+ Gem::Version.new("3.1.2"),
112
+ Gem::Version.new("4.1.0")
113
+ ].shuffle
114
+ end
115
+
116
+ it "returns the best possible match for the given constraints" do
117
+ Doubleshot::Resolver::GemResolver::Solver::satisfy_best([">= 1.0.0", "< 4.1.0"], @versions)
118
+ .to_s.must_equal "3.1.2"
119
+ end
120
+
121
+ it "raises a NoSolutionError error given no version matches a constraint" do
122
+ -> {
123
+ Doubleshot::Resolver::GemResolver::Solver::satisfy_best(">= 5.0.0", [Gem::Version.new("4.1.0")])
124
+ }.must_raise Doubleshot::Resolver::GemResolver::Errors::NoSolutionError
125
+ end
126
+ end
127
+ end
128
+
129
+ describe "#resolve" do
130
+ before do
131
+ @graph.artifacts("nginx", "1.0.0")
132
+ @solver.demands("nginx", "= 1.0.0")
133
+ end
134
+
135
+ it "returns a solution in the form of a Hash" do
136
+ @solver.resolve.must_be_kind_of Hash
137
+ end
138
+ end
139
+
140
+ describe "#demands" do
141
+ describe "given a name and constraint argument" do
142
+ before do
143
+ @name = "nginx"
144
+ @constraint = "~> 0.101.5"
145
+ @demand = @solver.demands(@name, @constraint)
146
+ end
147
+
148
+ describe "given the artifact of the given name and constraint does not exist" do
149
+ it "returns a Solve::Demand" do
150
+ @demand.must_be_kind_of Doubleshot::Resolver::GemResolver::Demand
151
+ end
152
+
153
+ it "the artifact has the given name" do
154
+ @demand.name.must_equal @name
155
+ end
156
+
157
+ it "the artifact has the given constraint" do
158
+ @demand.constraint.to_s.must_equal @constraint
159
+ end
160
+
161
+ it "adds an artifact to the demands collection" do
162
+ @solver.demands.size.must_equal 1
163
+ end
164
+
165
+ it "the artifact added matches the given name" do
166
+ @solver.demands[0].name.must_equal @name
167
+ end
168
+
169
+ it "the artifact added matches the given constraint" do
170
+ @solver.demands[0].constraint.to_s.must_equal @constraint
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "given only a name argument" do
176
+ it "returns a demand with a match all version constraint (>= 0)" do
177
+ @solver.demands("nginx").constraint.to_s.must_equal ">= 0"
178
+ end
179
+ end
180
+
181
+ describe "given no arguments" do
182
+ it "returns an array" do
183
+ @solver.demands.must_be_kind_of Array
184
+ end
185
+
186
+ it "returns an empty array if no demands have been accessed" do
187
+ @solver.demands.size.must_equal 0
188
+ end
189
+
190
+ it "returns an array containing a demand if one was accessed" do
191
+ @solver.demands("nginx", "~> 0.101.5")
192
+ @solver.demands.size.must_equal 1
193
+ end
194
+ end
195
+
196
+ describe "given an unexpected number of arguments" do
197
+ it "raises an ArgumentError if more than two are provided" do
198
+ -> {
199
+ @solver.demands(1, 2, 3)
200
+ }.must_raise ArgumentError, "Unexpected number of arguments. You gave: 3. Expected: 2 or less."
201
+ end
202
+
203
+ it "raises an ArgumentError if a name argument of nil is provided" do
204
+ -> {
205
+ @solver.demands(nil)
206
+ }.must_raise ArgumentError, "A name must be specified. You gave: [nil]."
207
+ end
208
+
209
+ it "raises an ArgumentError if a name and constraint argument are provided but name is nil" do
210
+ -> {
211
+ @solver.demands(nil, "= 1.0.0")
212
+ }.must_raise ArgumentError, 'A name must be specified. You gave: [nil, "= 1.0.0"].'
213
+ end
214
+ end
215
+ end
216
+
217
+ describe "#add_demand" do
218
+ before do
219
+ @demand = Doubleshot::Resolver::GemResolver::Demand.new(MiniTest::Mock, "ntp")
220
+ end
221
+
222
+ it "adds a Solve::Artifact to the collection of artifacts" do
223
+ @solver.add_demand @demand
224
+
225
+ @solver.demands.must_include @demand
226
+ @solver.demands.size.must_equal 1
227
+ end
228
+
229
+ it "should not add the same demand twice to the collection" do
230
+ @solver.add_demand @demand
231
+ @solver.add_demand @demand
232
+
233
+ @solver.demands.must_include @demand
234
+ @solver.demands.size.must_equal 1
235
+ end
236
+ end
237
+
238
+ describe "#remove_demand" do
239
+ before do
240
+ @demand = Doubleshot::Resolver::GemResolver::Demand.new(MiniTest::Mock, "ntp")
241
+ end
242
+
243
+ describe "given the demand is a member of the collection" do
244
+ before do
245
+ @solver.add_demand @demand
246
+ end
247
+
248
+ it "removes the Solve::Artifact from the collection of demands" do
249
+ @solver.remove_demand @demand
250
+ @solver.demands.size.must_equal 0
251
+ end
252
+
253
+ it "returns the removed Solve::Artifact" do
254
+ @solver.remove_demand(@demand).must_equal @demand
255
+ end
256
+ end
257
+
258
+ it "should return nil given the demand is not a member of the collection" do
259
+ @solver.remove_demand(@demand).must_be_nil
260
+ end
261
+ end
262
+
263
+ describe "#has_demand?" do
264
+ before do
265
+ @demand = Doubleshot::Resolver::GemResolver::Demand.new(MiniTest::Mock, "ntp")
266
+ end
267
+
268
+ it "returns true if the given Solve::Artifact is a member of the collection" do
269
+ @solver.add_demand @demand
270
+
271
+ @solver.has_demand?(@demand).must_equal true
272
+ end
273
+
274
+ it "returns false if the given Solve::Artifact is not a member of the collection" do
275
+ @solver.has_demand?(@demand).must_equal false
276
+ end
277
+ end
278
+
279
+ describe "solutions" do
280
+ it "chooses the correct artifact for the demands" do
281
+ @graph.artifacts("mysql", "2.0.0")
282
+ @graph.artifacts("mysql", "1.2.0")
283
+ @graph.artifacts("nginx", "1.0.0").depends("mysql", "= 1.2.0")
284
+
285
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [['nginx', '= 1.0.0'], ['mysql']]).resolve
286
+
287
+ result.must_equal({"nginx" => "1.0.0", "mysql" => "1.2.0"})
288
+ end
289
+
290
+ it "chooses the best artifact for the demands" do
291
+ @graph.artifacts("mysql", "2.0.0")
292
+ @graph.artifacts("mysql", "1.2.0")
293
+ @graph.artifacts("nginx", "1.0.0").depends("mysql", ">= 1.2.0")
294
+
295
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [['nginx', '= 1.0.0'], ['mysql']]).resolve
296
+
297
+ result.must_equal({"nginx" => "1.0.0", "mysql" => "2.0.0"})
298
+ end
299
+
300
+ it "raises NoSolutionError when a solution cannot be found" do
301
+ @graph.artifacts("mysql", "1.2.0")
302
+
303
+ -> {
304
+ Doubleshot::Resolver::GemResolver::Solver.new(@graph, ['mysql', '>= 2.0.0']).resolve
305
+ }.must_raise Doubleshot::Resolver::GemResolver::Errors::NoSolutionError
306
+ end
307
+
308
+ it "find the correct solution when backtracking in variables introduced via demands" do
309
+ @graph.artifacts("D", "1.2.0")
310
+ @graph.artifacts("D", "1.3.0")
311
+ @graph.artifacts("D", "1.4.0")
312
+ @graph.artifacts("D", "2.0.0")
313
+ @graph.artifacts("D", "2.1.0")
314
+
315
+ @graph.artifacts("C", "2.0.0").depends("D", "= 1.2.0")
316
+ @graph.artifacts("C", "2.1.0").depends("D", ">= 2.1.0")
317
+ @graph.artifacts("C", "2.2.0").depends("D", "> 2.0.0")
318
+
319
+ @graph.artifacts("B", "1.0.0").depends("D", "= 1.0.0")
320
+ @graph.artifacts("B", "1.1.0").depends("D", "= 1.0.0")
321
+ @graph.artifacts("B", "2.0.0").depends("D", ">= 1.3.0")
322
+ @graph.artifacts("B", "2.1.0").depends("D", ">= 2.0.0")
323
+
324
+ @graph.artifacts("A", "1.0.0").depends("B", "> 2.0.0")
325
+ @graph.artifacts("A", "1.0.0").depends("C", "= 2.1.0")
326
+ @graph.artifacts("A", "1.0.1").depends("B", "> 1.0.0")
327
+ @graph.artifacts("A", "1.0.1").depends("C", "= 2.1.0")
328
+ @graph.artifacts("A", "1.0.2").depends("B", "> 1.0.0")
329
+ @graph.artifacts("A", "1.0.2").depends("C", "= 2.0.0")
330
+
331
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [['A', '~> 1.0.0'], ['D', ">= 2.0.0"]]).resolve
332
+
333
+ result.must_equal({"A" => "1.0.1",
334
+ "B" => "2.1.0",
335
+ "C" => "2.1.0",
336
+ "D" => "2.1.0"})
337
+ end
338
+
339
+ it "must correctly resolve when one resolution exists but it is not the latest" do
340
+ skip "pending: https://github.com/reset/solve/pull/7"
341
+
342
+ @graph.artifacts("get-the-old-one", "1.0")
343
+ .depends("locked-mid-1", ">= 0")
344
+ .depends("locked-mid-2", ">= 0")
345
+ @graph.artifacts("get-the-old-one", "0.5")
346
+
347
+ @graph.artifacts("locked-mid-1", "2.0").depends("old-bottom", "= 2.0")
348
+ @graph.artifacts("locked-mid-1", "1.3").depends("old-bottom", "= 0.5")
349
+ @graph.artifacts("locked-mid-1", "1.0")
350
+
351
+ @graph.artifacts("locked-mid-2", "2.0").depends("old-bottom", "= 2.1")
352
+ @graph.artifacts("locked-mid-2", "1.4").depends("old-bottom", "= 0.5")
353
+ @graph.artifacts("locked-mid-2", "1.0")
354
+
355
+ @graph.artifacts("old-bottom", "2.1")
356
+ @graph.artifacts("old-bottom", "2.0")
357
+ @graph.artifacts("old-bottom", "1.0")
358
+ @graph.artifacts("old-bottom", "0.5")
359
+
360
+ Doubleshot::Resolver::GemResolver::Solver.new(@graph, ["get-the-old-one"]).resolve.must_equal(
361
+ {
362
+ "get-the-old-one" => "1.0",
363
+ "locked-mid-1" => "1.3",
364
+ "locked-mid-2" => "1.4",
365
+ "old-bottom" => "0.5"
366
+ })
367
+ end
368
+
369
+ it "finds the correct solution when there is a circular dependency" do
370
+ @graph.artifacts("A", "1.0.0").depends("B", "1.0.0")
371
+ @graph.artifacts("B", "1.0.0").depends("C", "1.0.0")
372
+ @graph.artifacts("C", "1.0.0").depends("A", "1.0.0")
373
+
374
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["A", "1.0.0"]]).resolve
375
+
376
+ result.must_equal({"A" => "1.0.0",
377
+ "B" => "1.0.0",
378
+ "C" => "1.0.0"})
379
+ end
380
+
381
+ it "finds the correct solution when there is a p shaped dependency chain" do
382
+ @graph.artifacts("A", "1.0.0").depends("B", "1.0.0")
383
+ @graph.artifacts("B", "1.0.0").depends("C", "1.0.0")
384
+ @graph.artifacts("C", "1.0.0").depends("B", "1.0.0")
385
+
386
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["A", "1.0.0"]]).resolve
387
+
388
+ result.must_equal({"A" => "1.0.0",
389
+ "B" => "1.0.0",
390
+ "C" => "1.0.0"})
391
+ end
392
+
393
+ it "finds the correct solution when there is a diamond shaped dependency" do
394
+ @graph.artifacts("A", "1.0.0")
395
+ .depends("B", "1.0.0")
396
+ .depends("C", "1.0.0")
397
+ @graph.artifacts("B", "1.0.0")
398
+ .depends("D", "1.0.0")
399
+ @graph.artifacts("C", "1.0.0")
400
+ .depends("D", "1.0.0")
401
+ @graph.artifacts("D", "1.0.0")
402
+
403
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["A", "1.0.0"]]).resolve
404
+
405
+ result.must_equal({"A" => "1.0.0",
406
+ "B" => "1.0.0",
407
+ "C" => "1.0.0",
408
+ "D" => "1.0.0"})
409
+ end
410
+
411
+ it "gives an empty solution when there are no demands" do
412
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, []).resolve
413
+ result.must_equal({})
414
+ end
415
+
416
+ it "tries all combinations until it finds a solution" do
417
+ @graph.artifacts("A", "1.0.0").depends("B", "~> 1.0.0")
418
+ @graph.artifacts("A", "1.0.1").depends("B", "~> 1.0.0")
419
+ @graph.artifacts("A", "1.0.2").depends("B", "~> 1.0.0")
420
+
421
+ @graph.artifacts("B", "1.0.0").depends("C", "~> 1.0.0")
422
+ @graph.artifacts("B", "1.0.1").depends("C", "~> 1.0.0")
423
+ @graph.artifacts("B", "1.0.2").depends("C", "~> 1.0.0")
424
+
425
+ @graph.artifacts("C", "1.0.0").depends("D", "1.0.0")
426
+ @graph.artifacts("C", "1.0.1").depends("D", "1.0.0")
427
+ @graph.artifacts("C", "1.0.2").depends("D", "1.0.0")
428
+
429
+ # ensure we can't find a solution in the above
430
+ @graph.artifacts("D", "1.0.0").depends("A", "< 0.0.0")
431
+
432
+ # Add a solution to the graph that should be reached only after
433
+ # all of the others have been tried
434
+ # it must be circular to ensure that no other branch can find it
435
+ @graph.artifacts("A", "0.0.0").depends("B", "0.0.0")
436
+ @graph.artifacts("B", "0.0.0").depends("C", "0.0.0")
437
+ @graph.artifacts("C", "0.0.0").depends("D", "0.0.0")
438
+ @graph.artifacts("D", "0.0.0").depends("A", "0.0.0")
439
+
440
+ result = Doubleshot::Resolver::GemResolver::Solver.new(@graph, [["A"]]).resolve
441
+
442
+ result.must_equal({ "A" => "0.0.0",
443
+ "B" => "0.0.0",
444
+ "C" => "0.0.0",
445
+ "D" => "0.0.0"})
446
+
447
+ end
448
+ end
449
+ end