librarianp 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +255 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +235 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +55 -0
  10. data/Rakefile +28 -0
  11. data/VERSION +1 -0
  12. data/lib/librarian/action/base.rb +24 -0
  13. data/lib/librarian/action/clean.rb +44 -0
  14. data/lib/librarian/action/ensure.rb +24 -0
  15. data/lib/librarian/action/install.rb +95 -0
  16. data/lib/librarian/action/persist_resolution_mixin.rb +51 -0
  17. data/lib/librarian/action/resolve.rb +46 -0
  18. data/lib/librarian/action/update.rb +44 -0
  19. data/lib/librarian/action.rb +5 -0
  20. data/lib/librarian/algorithms.rb +133 -0
  21. data/lib/librarian/cli/manifest_presenter.rb +89 -0
  22. data/lib/librarian/cli.rb +225 -0
  23. data/lib/librarian/config/database.rb +205 -0
  24. data/lib/librarian/config/file_source.rb +47 -0
  25. data/lib/librarian/config/hash_source.rb +33 -0
  26. data/lib/librarian/config/source.rb +149 -0
  27. data/lib/librarian/config.rb +7 -0
  28. data/lib/librarian/dependency.rb +153 -0
  29. data/lib/librarian/dsl/receiver.rb +42 -0
  30. data/lib/librarian/dsl/target.rb +171 -0
  31. data/lib/librarian/dsl.rb +102 -0
  32. data/lib/librarian/environment/runtime_cache.rb +101 -0
  33. data/lib/librarian/environment.rb +230 -0
  34. data/lib/librarian/error.rb +4 -0
  35. data/lib/librarian/helpers.rb +29 -0
  36. data/lib/librarian/linter/source_linter.rb +55 -0
  37. data/lib/librarian/lockfile/compiler.rb +66 -0
  38. data/lib/librarian/lockfile/parser.rb +123 -0
  39. data/lib/librarian/lockfile.rb +29 -0
  40. data/lib/librarian/logger.rb +46 -0
  41. data/lib/librarian/manifest.rb +146 -0
  42. data/lib/librarian/manifest_set.rb +150 -0
  43. data/lib/librarian/mock/cli.rb +19 -0
  44. data/lib/librarian/mock/dsl.rb +15 -0
  45. data/lib/librarian/mock/environment.rb +21 -0
  46. data/lib/librarian/mock/extension.rb +9 -0
  47. data/lib/librarian/mock/source/mock/registry.rb +83 -0
  48. data/lib/librarian/mock/source/mock.rb +80 -0
  49. data/lib/librarian/mock/source.rb +1 -0
  50. data/lib/librarian/mock/version.rb +5 -0
  51. data/lib/librarian/mock.rb +1 -0
  52. data/lib/librarian/posix.rb +129 -0
  53. data/lib/librarian/resolution.rb +46 -0
  54. data/lib/librarian/resolver/implementation.rb +238 -0
  55. data/lib/librarian/resolver.rb +94 -0
  56. data/lib/librarian/rspec/support/cli_macro.rb +120 -0
  57. data/lib/librarian/source/basic_api.rb +45 -0
  58. data/lib/librarian/source/git/repository.rb +193 -0
  59. data/lib/librarian/source/git.rb +172 -0
  60. data/lib/librarian/source/local.rb +54 -0
  61. data/lib/librarian/source/path.rb +56 -0
  62. data/lib/librarian/source.rb +2 -0
  63. data/lib/librarian/spec.rb +13 -0
  64. data/lib/librarian/spec_change_set.rb +173 -0
  65. data/lib/librarian/specfile.rb +19 -0
  66. data/lib/librarian/support/abstract_method.rb +21 -0
  67. data/lib/librarian/ui.rb +64 -0
  68. data/lib/librarian/version.rb +3 -0
  69. data/lib/librarian.rb +11 -0
  70. data/librarian.gemspec +47 -0
  71. data/spec/functional/cli_spec.rb +27 -0
  72. data/spec/functional/posix_spec.rb +32 -0
  73. data/spec/functional/source/git/repository_spec.rb +199 -0
  74. data/spec/functional/source/git_spec.rb +174 -0
  75. data/spec/support/fakefs.rb +37 -0
  76. data/spec/support/method_patch_macro.rb +30 -0
  77. data/spec/support/project_path_macro.rb +14 -0
  78. data/spec/support/with_env_macro.rb +22 -0
  79. data/spec/unit/action/base_spec.rb +18 -0
  80. data/spec/unit/action/clean_spec.rb +102 -0
  81. data/spec/unit/action/ensure_spec.rb +37 -0
  82. data/spec/unit/action/install_spec.rb +111 -0
  83. data/spec/unit/algorithms_spec.rb +131 -0
  84. data/spec/unit/config/database_spec.rb +320 -0
  85. data/spec/unit/dependency/requirement_spec.rb +12 -0
  86. data/spec/unit/dependency_spec.rb +212 -0
  87. data/spec/unit/dsl_spec.rb +173 -0
  88. data/spec/unit/environment/runtime_cache_spec.rb +73 -0
  89. data/spec/unit/environment_spec.rb +209 -0
  90. data/spec/unit/lockfile/parser_spec.rb +162 -0
  91. data/spec/unit/lockfile_spec.rb +65 -0
  92. data/spec/unit/manifest/version_spec.rb +11 -0
  93. data/spec/unit/manifest_set_spec.rb +202 -0
  94. data/spec/unit/manifest_spec.rb +36 -0
  95. data/spec/unit/mock/environment_spec.rb +25 -0
  96. data/spec/unit/mock/source/mock_spec.rb +22 -0
  97. data/spec/unit/resolver_spec.rb +299 -0
  98. data/spec/unit/source/git_spec.rb +29 -0
  99. data/spec/unit/spec_change_set_spec.rb +169 -0
  100. metadata +257 -0
@@ -0,0 +1,173 @@
1
+ require 'librarian'
2
+ require 'librarian/mock'
3
+
4
+ module Librarian
5
+ module Mock
6
+
7
+ describe Dsl do
8
+
9
+ let(:env) { Environment.new }
10
+
11
+ context "a single source and a single dependency with a blank name" do
12
+ it "should not not run with a blank name" do
13
+ expect do
14
+ env.dsl do
15
+ src 'source-1'
16
+ dep ''
17
+ end
18
+ end.to raise_error(ArgumentError, %{name ("") must be sensible})
19
+ end
20
+ end
21
+
22
+ context "a simple specfile - a single source, a single dependency, no transitive dependencies" do
23
+
24
+ it "should run with a hash source" do
25
+ spec = env.dsl do
26
+ dep 'dependency-1',
27
+ :src => 'source-1'
28
+ end
29
+ expect(spec.dependencies).to_not be_empty
30
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
31
+ expect(spec.dependencies.first.source.name).to eq 'source-1'
32
+ expect(spec.sources).to be_empty
33
+ end
34
+
35
+ it "should run with a shortcut source" do
36
+ spec = env.dsl do
37
+ dep 'dependency-1',
38
+ :source => :a
39
+ end
40
+ expect(spec.dependencies).to_not be_empty
41
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
42
+ expect(spec.dependencies.first.source.name).to eq 'source-a'
43
+ expect(spec.sources).to be_empty
44
+ end
45
+
46
+ it "should run with a block hash source" do
47
+ spec = env.dsl do
48
+ source :src => 'source-1' do
49
+ dep 'dependency-1'
50
+ end
51
+ end
52
+ expect(spec.dependencies).to_not be_empty
53
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
54
+ expect(spec.dependencies.first.source.name).to eq 'source-1'
55
+ expect(spec.sources).to be_empty
56
+ end
57
+
58
+ it "should run with a block named source" do
59
+ spec = env.dsl do
60
+ src 'source-1' do
61
+ dep 'dependency-1'
62
+ end
63
+ end
64
+ expect(spec.dependencies).to_not be_empty
65
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
66
+ expect(spec.dependencies.first.source.name).to eq 'source-1'
67
+ expect(spec.sources).to be_empty
68
+ end
69
+
70
+ it "should run with a default hash source" do
71
+ spec = env.dsl do
72
+ source :src => 'source-1'
73
+ dep 'dependency-1'
74
+ end
75
+ expect(spec.dependencies).to_not be_empty
76
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
77
+ expect(spec.dependencies.first.source.name).to eq 'source-1'
78
+ expect(spec.sources).to_not be_empty
79
+ expect(spec.dependencies.first.source).to eq spec.sources.first
80
+ end
81
+
82
+ it "should run with a default named source" do
83
+ spec = env.dsl do
84
+ src 'source-1'
85
+ dep 'dependency-1'
86
+ end
87
+ expect(spec.dependencies).to_not be_empty
88
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
89
+ expect(spec.dependencies.first.source.name).to eq 'source-1'
90
+ expect(spec.sources).to_not be_empty
91
+ expect(spec.dependencies.first.source).to eq spec.sources.first
92
+ end
93
+
94
+ it "should run with a default shortcut source" do
95
+ spec = env.dsl do
96
+ source :a
97
+ dep 'dependency-1'
98
+ end
99
+ expect(spec.dependencies).to_not be_empty
100
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
101
+ expect(spec.dependencies.first.source.name).to eq 'source-a'
102
+ expect(spec.sources).to_not be_empty
103
+ expect(spec.dependencies.first.source).to eq spec.sources.first
104
+ end
105
+
106
+ it "should run with a shortcut source hash definition" do
107
+ spec = env.dsl do
108
+ source :b, :src => 'source-b'
109
+ dep 'dependency-1', :source => :b
110
+ end
111
+ expect(spec.dependencies).to_not be_empty
112
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
113
+ expect(spec.dependencies.first.source.name).to eq 'source-b'
114
+ expect(spec.sources).to be_empty
115
+ end
116
+
117
+ it "should run with a shortcut source block definition" do
118
+ spec = env.dsl do
119
+ source :b, proc { src 'source-b' }
120
+ dep 'dependency-1', :source => :b
121
+ end
122
+ expect(spec.dependencies).to_not be_empty
123
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
124
+ expect(spec.dependencies.first.source.name).to eq 'source-b'
125
+ expect(spec.sources).to be_empty
126
+ end
127
+
128
+ it "should run with a default shortcut source hash definition" do
129
+ spec = env.dsl do
130
+ source :b, :src => 'source-b'
131
+ source :b
132
+ dep 'dependency-1'
133
+ end
134
+ expect(spec.dependencies).to_not be_empty
135
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
136
+ expect(spec.dependencies.first.source.name).to eq 'source-b'
137
+ expect(spec.sources).to_not be_empty
138
+ expect(spec.sources.first.name).to eq 'source-b'
139
+ end
140
+
141
+ it "should run with a default shortcut source block definition" do
142
+ spec = env.dsl do
143
+ source :b, proc { src 'source-b' }
144
+ source :b
145
+ dep 'dependency-1'
146
+ end
147
+ expect(spec.dependencies).to_not be_empty
148
+ expect(spec.dependencies.first.name).to eq 'dependency-1'
149
+ expect(spec.dependencies.first.source.name).to eq 'source-b'
150
+ expect(spec.sources).to_not be_empty
151
+ expect(spec.sources.first.name).to eq 'source-b'
152
+ end
153
+
154
+ end
155
+
156
+ context "validating source options" do
157
+
158
+ it "should raise when given unrecognized optiosn options" do
159
+ expect do
160
+ env.dsl do
161
+ dep 'dependency-1',
162
+ :src => 'source-1',
163
+ :huh => 'yikes'
164
+ end
165
+ end.to raise_error(Error, %{unrecognized options: huh})
166
+ end
167
+
168
+ end
169
+
170
+ end
171
+
172
+ end
173
+ end
@@ -0,0 +1,73 @@
1
+ require "librarian/environment/runtime_cache"
2
+
3
+ module Librarian
4
+ class Environment
5
+ describe RuntimeCache do
6
+
7
+ let(:rtc) { described_class.new }
8
+ let(:key) { ["brah", "nick"] }
9
+ let(:key_x) { ["brah", "phar"] }
10
+ let(:key_y) { ["rost", "phar"] }
11
+
12
+ def triple(keypair)
13
+ [rtc.include?(*keypair), rtc.get(*keypair), rtc.memo(*keypair){yield}]
14
+ end
15
+
16
+ context "originally" do
17
+ specify { expect(triple(key){9}).to eql([false, nil, 9]) }
18
+ end
19
+
20
+ context "after put" do
21
+ before { rtc.put(*key){6} }
22
+
23
+ specify { expect(triple(key){9}).to eql([true, 6, 6]) }
24
+ specify { expect(triple(key_x){9}).to eql([false, nil, 9]) }
25
+ specify { expect(triple(key_y){9}).to eql([false, nil, 9]) }
26
+ end
27
+
28
+ context "after put then delete" do
29
+ before { rtc.put(*key){6} }
30
+ before { rtc.delete *key }
31
+
32
+ specify { expect(triple(key){9}).to eql([false, nil, 9]) }
33
+ specify { expect(triple(key_x){9}).to eql([false, nil, 9]) }
34
+ specify { expect(triple(key_y){9}).to eql([false, nil, 9]) }
35
+ end
36
+
37
+ context "after memo" do
38
+ before { rtc.memo(*key){6} }
39
+
40
+ specify { expect(triple(key){9}).to eql([true, 6, 6]) }
41
+ specify { expect(triple(key_x){9}).to eql([false, nil, 9]) }
42
+ specify { expect(triple(key_y){9}).to eql([false, nil, 9]) }
43
+ end
44
+
45
+ context "after memo then delete" do
46
+ before { rtc.memo(*key){6} }
47
+ before { rtc.delete *key }
48
+
49
+ specify { expect(triple(key){9}).to eql([false, nil, 9]) }
50
+ specify { expect(triple(key_x){9}).to eql([false, nil, 9]) }
51
+ specify { expect(triple(key_y){9}).to eql([false, nil, 9]) }
52
+ end
53
+
54
+ context "with keyspace wrapper" do
55
+ let(:krtc) { rtc.keyspace("brah") }
56
+ let(:key) { "nick" }
57
+ let(:key_x) { "phar" }
58
+
59
+ def triple(keypair)
60
+ [krtc.include?(key), krtc.get(key), krtc.memo(key){yield}]
61
+ end
62
+
63
+ context "after put" do
64
+ before { krtc.put(key){6} }
65
+
66
+ specify { expect(triple(key){9}).to eql([true, 6, 6]) }
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,209 @@
1
+ require "librarian/environment"
2
+
3
+ require "support/with_env_macro"
4
+
5
+ module Librarian
6
+ describe Environment do
7
+ include ::Support::WithEnvMacro
8
+
9
+ let(:env) { described_class.new }
10
+
11
+ describe "#adapter_module" do
12
+ specify { expect(env.adapter_module).to be nil }
13
+ end
14
+
15
+ describe "#adapter_name" do
16
+ specify { expect(env.adapter_name).to be nil }
17
+ end
18
+
19
+ describe "#adapter_version" do
20
+ specify { expect(env.adapter_version).to be nil }
21
+ end
22
+
23
+ describe "computing the home" do
24
+
25
+ context "with the HOME env var" do
26
+ with_env "HOME" => "/path/to/home"
27
+
28
+ it "finds the home" do
29
+ env.stub(:adapter_name).and_return("cat")
30
+ expect(env.config_db.underlying_home.to_s).to eq "/path/to/home"
31
+ end
32
+ end
33
+
34
+ context "without the HOME env var" do
35
+ let!(:real_home) { File.expand_path("~") }
36
+ with_env "HOME" => nil
37
+
38
+ it "finds the home" do
39
+ env.stub(:adapter_name).and_return("cat")
40
+ expect(env.config_db.underlying_home.to_s).to eq real_home
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ describe "#http_proxy_uri" do
47
+
48
+ context "sanity" do
49
+ with_env "http_proxy" => nil
50
+
51
+ it "should have a nil http proxy uri" do
52
+ expect(env.http_proxy_uri).to be_nil
53
+ end
54
+ end
55
+
56
+ context "with a complex proxy" do
57
+ with_env "http_proxy" => "admin:secret@example.com"
58
+
59
+ it "should have the expcted http proxy uri" do
60
+ expect(env.http_proxy_uri).to eq URI("http://admin:secret@example.com")
61
+ end
62
+
63
+ it "should have the expected host" do
64
+ expect(env.http_proxy_uri.host).to eq "example.com"
65
+ end
66
+
67
+ it "should have the expected user" do
68
+ expect(env.http_proxy_uri.user).to eq "admin"
69
+ end
70
+
71
+ it "should have the expected password" do
72
+ expect(env.http_proxy_uri.password).to eq "secret"
73
+ end
74
+ end
75
+
76
+ context "with a split proxy" do
77
+ with_env "http_proxy" => "example.com",
78
+ "http_proxy_user" => "admin",
79
+ "http_proxy_pass" => "secret"
80
+
81
+ it "should have the expcted http proxy uri" do
82
+ expect(env.http_proxy_uri).to eq URI("http://admin:secret@example.com")
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ describe "#net_http_class" do
89
+ let(:proxied_host) { "www.example.com" }
90
+ context "sanity" do
91
+ with_env "http_proxy" => nil
92
+
93
+ it "should have the normal class" do
94
+ expect(env.net_http_class(proxied_host)).to be Net::HTTP
95
+ end
96
+
97
+ it "should not be marked as a proxy class" do
98
+ expect(env.net_http_class(proxied_host)).to_not be_proxy_class
99
+ end
100
+ end
101
+
102
+ context "with a complex proxy" do
103
+ with_env "http_proxy" => "admin:secret@example.com"
104
+
105
+ it "should not by marked as a proxy class for localhost" do
106
+ expect(env.net_http_class('localhost')).to_not be_proxy_class
107
+ end
108
+ it "should not have the normal class" do
109
+ expect(env.net_http_class(proxied_host)).to_not be Net::HTTP
110
+ end
111
+
112
+ it "should have a subclass the normal class" do
113
+ expect(env.net_http_class(proxied_host)).to be < Net::HTTP
114
+ end
115
+
116
+ it "should be marked as a proxy class" do
117
+ expect(env.net_http_class(proxied_host)).to be_proxy_class
118
+ end
119
+
120
+ it "should have the expected proxy attributes" do
121
+ http = env.net_http_class(proxied_host).new("www.kernel.org")
122
+ expected_attributes = {
123
+ "host" => env.http_proxy_uri.host,
124
+ "port" => env.http_proxy_uri.port,
125
+ "user" => env.http_proxy_uri.user,
126
+ "pass" => env.http_proxy_uri.password
127
+ }
128
+ actual_attributes = {
129
+ "host" => http.proxy_address,
130
+ "port" => http.proxy_port,
131
+ "user" => http.proxy_user,
132
+ "pass" => http.proxy_pass,
133
+ }
134
+
135
+ expect(actual_attributes).to eq expected_attributes
136
+ end
137
+
138
+ end
139
+
140
+ context "with an excluded host" do
141
+ with_env "http_proxy" => "admin:secret@example.com",
142
+ "no_proxy" => "no.proxy.com, noproxy.com"
143
+
144
+ context "with an exact match" do
145
+ let(:proxied_host) { "noproxy.com" }
146
+
147
+ it "should have the normal class" do
148
+ expect(env.net_http_class(proxied_host)).to be Net::HTTP
149
+ end
150
+
151
+ it "should not be marked as a proxy class" do
152
+ expect(env.net_http_class(proxied_host)).to_not be_proxy_class
153
+ end
154
+ end
155
+
156
+ context "with a subdomain match" do
157
+ let(:proxied_host) { "www.noproxy.com" }
158
+
159
+ it "should have the normal class" do
160
+ expect(env.net_http_class(proxied_host)).to be Net::HTTP
161
+ end
162
+
163
+ it "should not be marked as a proxy class" do
164
+ expect(env.net_http_class(proxied_host)).to_not be_proxy_class
165
+ end
166
+ end
167
+
168
+ context "with localhost" do
169
+ let(:proxied_host) { "localhost" }
170
+
171
+ it "should have the normal class" do
172
+ expect(env.net_http_class(proxied_host)).to be Net::HTTP
173
+ end
174
+
175
+ it "should not be marked as a proxy class" do
176
+ expect(env.net_http_class(proxied_host)).to_not be_proxy_class
177
+ end
178
+ end
179
+
180
+ context "with 127.0.0.1" do
181
+ let(:proxied_host) { "127.0.0.1" }
182
+
183
+ it "should have the normal class" do
184
+ expect(env.net_http_class(proxied_host)).to be Net::HTTP
185
+ end
186
+
187
+ it "should not be marked as a proxy class" do
188
+ expect(env.net_http_class(proxied_host)).to_not be_proxy_class
189
+ end
190
+ end
191
+
192
+ context "with a mismatch" do
193
+ let(:proxied_host) { "www.example.com" }
194
+
195
+ it "should have a subclass the normal class" do
196
+ expect(env.net_http_class(proxied_host)).to be < Net::HTTP
197
+ end
198
+
199
+ it "should be marked as a proxy class" do
200
+ expect(env.net_http_class(proxied_host)).to be_proxy_class
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+
208
+ end
209
+ end
@@ -0,0 +1,162 @@
1
+ require "librarian/helpers"
2
+ require "librarian/lockfile/parser"
3
+ require "librarian/mock"
4
+
5
+ module Librarian
6
+ describe Lockfile::Parser do
7
+
8
+ let(:env) { Mock::Environment.new }
9
+ let(:parser) { described_class.new(env) }
10
+ let(:resolution) { parser.parse(lockfile) }
11
+
12
+ context "a mock lockfile with one source and no dependencies" do
13
+ let(:lockfile) do
14
+ Helpers.strip_heredoc <<-LOCKFILE
15
+ MOCK
16
+ remote: source-a
17
+ specs:
18
+
19
+ DEPENDENCIES
20
+
21
+ LOCKFILE
22
+ end
23
+
24
+ it "should give an empty list of dependencies" do
25
+ expect(resolution.dependencies).to be_empty
26
+ end
27
+
28
+ it "should give an empty list of manifests" do
29
+ expect(resolution.manifests).to be_empty
30
+ end
31
+ end
32
+
33
+ context "a mock lockfile with one source and one dependency" do
34
+ let(:lockfile) do
35
+ Helpers.strip_heredoc <<-LOCKFILE
36
+ MOCK
37
+ remote: source-a
38
+ specs:
39
+ jelly (1.3.5)
40
+
41
+ DEPENDENCIES
42
+ jelly (!= 1.2.6, ~> 1.1)
43
+
44
+ LOCKFILE
45
+ end
46
+
47
+ it "should give a list of one dependency" do
48
+ expect(resolution).to have(1).dependencies
49
+ end
50
+
51
+ it "should give a dependency with the expected name" do
52
+ dependency = resolution.dependencies.first
53
+
54
+ expect(dependency.name).to eq "jelly"
55
+ end
56
+
57
+ it "should give a dependency with the expected requirement" do
58
+ dependency = resolution.dependencies.first
59
+
60
+ # Note: it must be this order because this order is lexicographically sorted.
61
+ expect(dependency.requirement.to_s).to eq "!= 1.2.6, ~> 1.1"
62
+ end
63
+
64
+ it "should give a dependency wth the expected source" do
65
+ dependency = resolution.dependencies.first
66
+ source = dependency.source
67
+
68
+ expect(source.name).to eq "source-a"
69
+ end
70
+
71
+ it "should give a list of one manifest" do
72
+ expect(resolution).to have(1).manifests
73
+ end
74
+
75
+ it "should give a manifest with the expected name" do
76
+ manifest = resolution.manifests.first
77
+
78
+ expect(manifest.name).to eq "jelly"
79
+ end
80
+
81
+ it "should give a manifest with the expected version" do
82
+ manifest = resolution.manifests.first
83
+
84
+ expect(manifest.version.to_s).to eq "1.3.5"
85
+ end
86
+
87
+ it "should give a manifest with no dependencies" do
88
+ manifest = resolution.manifests.first
89
+
90
+ expect(manifest.dependencies).to be_empty
91
+ end
92
+
93
+ it "should give a manifest with the expected source" do
94
+ manifest = resolution.manifests.first
95
+ source = manifest.source
96
+
97
+ expect(source.name).to eq "source-a"
98
+ end
99
+
100
+ it "should give the dependency and the manifest the same source instance" do
101
+ dependency = resolution.dependencies.first
102
+ manifest = resolution.manifests.first
103
+
104
+ dependency_source = dependency.source
105
+ manifest_source = manifest.source
106
+
107
+ expect(manifest_source).to be dependency_source
108
+ end
109
+ end
110
+
111
+ context "a mock lockfile with one source and a complex dependency" do
112
+ let(:lockfile) do
113
+ Helpers.strip_heredoc <<-LOCKFILE
114
+ MOCK
115
+ remote: source-a
116
+ specs:
117
+ butter (2.5.3)
118
+ jelly (1.3.5)
119
+ butter (< 3, >= 1.1)
120
+
121
+ DEPENDENCIES
122
+ jelly (!= 1.2.6, ~> 1.1)
123
+
124
+ LOCKFILE
125
+ end
126
+
127
+ it "should give a list of one dependency" do
128
+ expect(resolution).to have(1).dependencies
129
+ end
130
+
131
+ it "should have the expected dependency" do
132
+ dependency = resolution.dependencies.first
133
+
134
+ expect(dependency.name).to eq "jelly"
135
+ end
136
+
137
+ it "should give a list of all the manifests" do
138
+ expect(resolution).to have(2).manifests
139
+ end
140
+
141
+ it "should include all the expected manifests" do
142
+ manifests = ManifestSet.new(resolution.manifests)
143
+
144
+ expect(manifests.to_hash.keys).to match_array( %w(butter jelly) )
145
+ end
146
+
147
+ it "should have an internally consistent set of manifests" do
148
+ manifests = ManifestSet.new(resolution.manifests)
149
+
150
+ expect(manifests).to be_consistent
151
+ end
152
+
153
+ it "should have an externally consistent set of manifests" do
154
+ dependencies = resolution.dependencies
155
+ manifests = ManifestSet.new(resolution.manifests)
156
+
157
+ expect(manifests).to be_in_compliance_with dependencies
158
+ end
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,65 @@
1
+ require 'librarian'
2
+ require 'librarian/mock'
3
+
4
+ module Librarian
5
+ describe Lockfile do
6
+
7
+ let(:env) { Mock::Environment.new }
8
+
9
+ before do
10
+ env.registry :clear => true do
11
+ source 'source-1' do
12
+ spec 'alpha', '1.1'
13
+ end
14
+ end
15
+ end
16
+
17
+ let(:spec) do
18
+ env.dsl do
19
+ src 'source-1'
20
+ dep 'alpha', '1.1'
21
+ end
22
+ end
23
+
24
+ let(:resolver) { env.resolver }
25
+ let(:resolution) { resolver.resolve(spec) }
26
+
27
+ context "sanity" do
28
+ context "the resolution" do
29
+ subject { resolution }
30
+
31
+ it { should be_correct }
32
+ it { should have(1).manifests }
33
+ end
34
+ end
35
+
36
+ describe "#save" do
37
+ let(:lockfile) { env.ephemeral_lockfile }
38
+ let(:lockfile_text) { lockfile.save(resolution) }
39
+
40
+ context "just saving" do
41
+ it "should return the lockfile text" do
42
+ expect(lockfile_text).to_not be_nil
43
+ end
44
+ end
45
+
46
+ context "saving and reloading" do
47
+ let(:reloaded_resolution) { lockfile.load(lockfile_text) }
48
+
49
+ it "should have the expected manifests" do
50
+ expect(reloaded_resolution.manifests.count).to eq resolution.manifests.count
51
+ end
52
+ end
53
+
54
+ context "bouncing" do
55
+ let(:bounced_resolution) { lockfile.load(lockfile_text) }
56
+ let(:bounced_lockfile_text) { lockfile.save(bounced_resolution) }
57
+
58
+ it "should return the same lockfile text after bouncing as before bouncing" do
59
+ expect(bounced_lockfile_text).to eq lockfile_text
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,11 @@
1
+ require "librarian/manifest"
2
+
3
+ describe Librarian::Manifest::Version do
4
+
5
+ describe "#inspect" do
6
+ subject(:version) { described_class.new("3.2.1") }
7
+
8
+ specify { expect(version.inspect).to eq "#<Librarian::Manifest::Version 3.2.1>" }
9
+ end
10
+
11
+ end