ronin-core 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +41 -0
  4. data/.gitignore +12 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +160 -0
  7. data/.ruby-version +1 -0
  8. data/.yardopts +1 -0
  9. data/COPYING.txt +165 -0
  10. data/ChangeLog.md +11 -0
  11. data/Gemfile +30 -0
  12. data/README.md +299 -0
  13. data/Rakefile +34 -0
  14. data/examples/ruby_shell.rb +11 -0
  15. data/gemspec.yml +28 -0
  16. data/lib/ronin/core/class_registry.rb +246 -0
  17. data/lib/ronin/core/cli/command.rb +87 -0
  18. data/lib/ronin/core/cli/command_shell/command.rb +110 -0
  19. data/lib/ronin/core/cli/command_shell.rb +345 -0
  20. data/lib/ronin/core/cli/generator/options/author.rb +106 -0
  21. data/lib/ronin/core/cli/generator/options/description.rb +54 -0
  22. data/lib/ronin/core/cli/generator/options/reference.rb +60 -0
  23. data/lib/ronin/core/cli/generator/options/summary.rb +54 -0
  24. data/lib/ronin/core/cli/generator.rb +238 -0
  25. data/lib/ronin/core/cli/logging.rb +59 -0
  26. data/lib/ronin/core/cli/options/param.rb +68 -0
  27. data/lib/ronin/core/cli/options/values/arches.rb +45 -0
  28. data/lib/ronin/core/cli/options/values/oses.rb +32 -0
  29. data/lib/ronin/core/cli/printing/arch.rb +71 -0
  30. data/lib/ronin/core/cli/printing/metadata.rb +113 -0
  31. data/lib/ronin/core/cli/printing/os.rb +54 -0
  32. data/lib/ronin/core/cli/printing/params.rb +69 -0
  33. data/lib/ronin/core/cli/ruby_shell.rb +131 -0
  34. data/lib/ronin/core/cli/shell.rb +186 -0
  35. data/lib/ronin/core/git.rb +73 -0
  36. data/lib/ronin/core/home.rb +86 -0
  37. data/lib/ronin/core/metadata/authors/author.rb +241 -0
  38. data/lib/ronin/core/metadata/authors.rb +120 -0
  39. data/lib/ronin/core/metadata/description.rb +100 -0
  40. data/lib/ronin/core/metadata/id.rb +88 -0
  41. data/lib/ronin/core/metadata/references.rb +87 -0
  42. data/lib/ronin/core/metadata/summary.rb +78 -0
  43. data/lib/ronin/core/metadata/version.rb +74 -0
  44. data/lib/ronin/core/params/exceptions.rb +38 -0
  45. data/lib/ronin/core/params/mixin.rb +317 -0
  46. data/lib/ronin/core/params/param.rb +137 -0
  47. data/lib/ronin/core/params/types/boolean.rb +64 -0
  48. data/lib/ronin/core/params/types/enum.rb +107 -0
  49. data/lib/ronin/core/params/types/float.rb +68 -0
  50. data/lib/ronin/core/params/types/integer.rb +100 -0
  51. data/lib/ronin/core/params/types/numeric.rb +106 -0
  52. data/lib/ronin/core/params/types/regexp.rb +67 -0
  53. data/lib/ronin/core/params/types/string.rb +118 -0
  54. data/lib/ronin/core/params/types/type.rb +54 -0
  55. data/lib/ronin/core/params/types/uri.rb +72 -0
  56. data/lib/ronin/core/params/types.rb +62 -0
  57. data/lib/ronin/core/params.rb +19 -0
  58. data/lib/ronin/core/version.rb +24 -0
  59. data/ronin-core.gemspec +59 -0
  60. data/spec/class_registry_spec.rb +224 -0
  61. data/spec/cli/command_shell/command_spec.rb +113 -0
  62. data/spec/cli/command_shell_spec.rb +1114 -0
  63. data/spec/cli/command_spec.rb +16 -0
  64. data/spec/cli/fixtures/irb_command +8 -0
  65. data/spec/cli/fixtures/template/dir/file1.txt +1 -0
  66. data/spec/cli/fixtures/template/dir/file2.txt +1 -0
  67. data/spec/cli/fixtures/template/file.erb +1 -0
  68. data/spec/cli/fixtures/template/file.txt +1 -0
  69. data/spec/cli/generator/options/author_spec.rb +121 -0
  70. data/spec/cli/generator/options/description_spec.rb +45 -0
  71. data/spec/cli/generator/options/reference_spec.rb +53 -0
  72. data/spec/cli/generator/options/summary_spec.rb +45 -0
  73. data/spec/cli/generator_spec.rb +244 -0
  74. data/spec/cli/logging_spec.rb +95 -0
  75. data/spec/cli/options/param_spec.rb +67 -0
  76. data/spec/cli/options/values/arches_spec.rb +62 -0
  77. data/spec/cli/printing/arch_spec.rb +130 -0
  78. data/spec/cli/printing/metadata_spec.rb +211 -0
  79. data/spec/cli/printing/os_spec.rb +64 -0
  80. data/spec/cli/printing/params_spec.rb +63 -0
  81. data/spec/cli/ruby_shell.rb +99 -0
  82. data/spec/cli/shell_spec.rb +211 -0
  83. data/spec/fixtures/example_class_registry/base_class.rb +9 -0
  84. data/spec/fixtures/example_class_registry/classes/loaded_class.rb +9 -0
  85. data/spec/fixtures/example_class_registry/classes/name_mismatch.rb +9 -0
  86. data/spec/fixtures/example_class_registry/classes/no_module.rb +4 -0
  87. data/spec/fixtures/example_class_registry.rb +8 -0
  88. data/spec/git_spec.rb +58 -0
  89. data/spec/home_spec.rb +64 -0
  90. data/spec/metadata/authors/author_spec.rb +335 -0
  91. data/spec/metadata/authors_spec.rb +126 -0
  92. data/spec/metadata/description_spec.rb +74 -0
  93. data/spec/metadata/id_spec.rb +92 -0
  94. data/spec/metadata/references_spec.rb +100 -0
  95. data/spec/metadata/summary_spec.rb +74 -0
  96. data/spec/metadata/version_spec.rb +72 -0
  97. data/spec/params/mixin_spec.rb +484 -0
  98. data/spec/params/param_spec.rb +164 -0
  99. data/spec/params/types/boolean_spec.rb +56 -0
  100. data/spec/params/types/enum_spec.rb +94 -0
  101. data/spec/params/types/float_spec.rb +107 -0
  102. data/spec/params/types/integer_spec.rb +155 -0
  103. data/spec/params/types/numeric_spec.rb +138 -0
  104. data/spec/params/types/regexp_spec.rb +64 -0
  105. data/spec/params/types/string_spec.rb +174 -0
  106. data/spec/params/types/type_spec.rb +14 -0
  107. data/spec/params/types/uri_spec.rb +62 -0
  108. data/spec/spec_helper.rb +11 -0
  109. metadata +252 -0
@@ -0,0 +1,335 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/metadata/authors/author'
3
+
4
+ describe Ronin::Core::Metadata::Authors::Author do
5
+ let(:name) { 'John Smith' }
6
+ let(:email) { 'john.smith@example.com' }
7
+ let(:pgp) { '0x123456789' }
8
+ let(:website) { 'https://jsmith.name' }
9
+ let(:blog) { 'https://blog.jsmith.name' }
10
+ let(:github) { 'jsmith_github' }
11
+ let(:gitlab) { 'jsmith_gitlab' }
12
+ let(:twitter) { 'jsmith_twitter' }
13
+ let(:discord) { 'jsmith_discord' }
14
+
15
+ describe "#initialize" do
16
+ subject { described_class.new(name) }
17
+
18
+ it "must set #name" do
19
+ expect(subject.name).to eq(name)
20
+ end
21
+
22
+ context "when given the email: keyword argument" do
23
+ subject { described_class.new(name, email: email) }
24
+
25
+ it "must set #email" do
26
+ expect(subject.email).to eq(email)
27
+ end
28
+ end
29
+
30
+ context "when given the pgp: keyword argument" do
31
+ subject { described_class.new(name, pgp: pgp) }
32
+
33
+ it "must set #pgp" do
34
+ expect(subject.pgp).to eq(pgp)
35
+ end
36
+ end
37
+
38
+ context "when given the website: keyword argument" do
39
+ subject { described_class.new(name, website: website) }
40
+
41
+ it "must set #website" do
42
+ expect(subject.website).to eq(website)
43
+ end
44
+ end
45
+
46
+ context "when given the blog: keyword argument" do
47
+ subject { described_class.new(name, blog: blog) }
48
+
49
+ it "must set #blog" do
50
+ expect(subject.blog).to eq(blog)
51
+ end
52
+ end
53
+
54
+ context "when given the github: keyword argument" do
55
+ subject { described_class.new(name, github: github) }
56
+
57
+ it "must set #github" do
58
+ expect(subject.github).to eq(github)
59
+ end
60
+ end
61
+
62
+ context "when given the gitlab: keyword argument" do
63
+ subject { described_class.new(name, gitlab: gitlab) }
64
+
65
+ it "must set #gitlab" do
66
+ expect(subject.gitlab).to eq(gitlab)
67
+ end
68
+ end
69
+
70
+ context "when given the twitter: keyword argument" do
71
+ subject { described_class.new(name, twitter: twitter) }
72
+
73
+ it "must set #twitter" do
74
+ expect(subject.twitter).to eq(twitter)
75
+ end
76
+ end
77
+
78
+ context "when given the discord: keyword argument" do
79
+ subject { described_class.new(name, discord: discord) }
80
+
81
+ it "must set #discord" do
82
+ expect(subject.discord).to eq(discord)
83
+ end
84
+ end
85
+ end
86
+
87
+ subject do
88
+ described_class.new(name, email: email,
89
+ pgp: pgp,
90
+ github: github,
91
+ gitlab: gitlab,
92
+ twitter: twitter,
93
+ discord: discord)
94
+ end
95
+
96
+ describe "#email?" do
97
+ context "when #email is set" do
98
+ subject { described_class.new(name, email: email) }
99
+
100
+ it "must return true" do
101
+ expect(subject.email?).to be(true)
102
+ end
103
+ end
104
+
105
+ context "when #email is not set" do
106
+ subject { described_class.new(name) }
107
+
108
+ it "must return false" do
109
+ expect(subject.email?).to be(false)
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#pgp?" do
115
+ context "when #pgp is set" do
116
+ subject { described_class.new(name, pgp: pgp) }
117
+
118
+ it "must return true" do
119
+ expect(subject.pgp?).to be(true)
120
+ end
121
+ end
122
+
123
+ context "when #pgp is not set" do
124
+ subject { described_class.new(name) }
125
+
126
+ it "must return false" do
127
+ expect(subject.pgp?).to be(false)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#website?" do
133
+ context "when #website is set" do
134
+ subject { described_class.new(name, website: website) }
135
+
136
+ it "must return true" do
137
+ expect(subject.website?).to be(true)
138
+ end
139
+ end
140
+
141
+ context "when #website is not set" do
142
+ subject { described_class.new(name) }
143
+
144
+ it "must return false" do
145
+ expect(subject.website?).to be(false)
146
+ end
147
+ end
148
+ end
149
+
150
+ describe "#blog?" do
151
+ context "when #blog is set" do
152
+ subject { described_class.new(name, blog: blog) }
153
+
154
+ it "must return true" do
155
+ expect(subject.blog?).to be(true)
156
+ end
157
+ end
158
+
159
+ context "when #blog is not set" do
160
+ subject { described_class.new(name) }
161
+
162
+ it "must return false" do
163
+ expect(subject.blog?).to be(false)
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "#github?" do
169
+ context "when #github is set" do
170
+ subject { described_class.new(name, github: github) }
171
+
172
+ it "must return true" do
173
+ expect(subject.github?).to be(true)
174
+ end
175
+ end
176
+
177
+ context "when #github is not set" do
178
+ subject { described_class.new(name) }
179
+
180
+ it "must return false" do
181
+ expect(subject.github?).to be(false)
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "#gitlab?" do
187
+ context "when #gitlab is set" do
188
+ subject { described_class.new(name, gitlab: gitlab) }
189
+
190
+ it "must return true" do
191
+ expect(subject.gitlab?).to be(true)
192
+ end
193
+ end
194
+
195
+ context "when #gitlab is not set" do
196
+ subject { described_class.new(name) }
197
+
198
+ it "must return false" do
199
+ expect(subject.gitlab?).to be(false)
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#twitter?" do
205
+ context "when #twitter is set" do
206
+ subject { described_class.new(name, twitter: twitter) }
207
+
208
+ it "must return true" do
209
+ expect(subject.twitter?).to be(true)
210
+ end
211
+ end
212
+
213
+ context "when #twitter is not set" do
214
+ subject { described_class.new(name) }
215
+
216
+ it "must return false" do
217
+ expect(subject.twitter?).to be(false)
218
+ end
219
+ end
220
+ end
221
+
222
+ describe "#discord?" do
223
+ context "when #discord is set" do
224
+ subject { described_class.new(name, discord: discord) }
225
+
226
+ it "must return true" do
227
+ expect(subject.discord?).to be(true)
228
+ end
229
+ end
230
+
231
+ context "when #discord is not set" do
232
+ subject { described_class.new(name) }
233
+
234
+ it "must return false" do
235
+ expect(subject.discord?).to be(false)
236
+ end
237
+ end
238
+ end
239
+
240
+ describe "#github_url" do
241
+ context "when #github is set" do
242
+ subject { described_class.new(name, github: github) }
243
+
244
+ it "must return the 'https://github.com/...' URL" do
245
+ expect(subject.github_url).to eq("https://github.com/#{github}")
246
+ end
247
+
248
+ context "but the twitter handle starts with a '@'" do
249
+ subject { described_class.new(name, github: "@#{github}") }
250
+
251
+ it "must omit the leading '@' character" do
252
+ expect(subject.github_url).to eq("https://github.com/#{github}")
253
+ end
254
+ end
255
+ end
256
+
257
+ context "when #github is not set" do
258
+ subject { described_class.new(name) }
259
+
260
+ it "must return nil" do
261
+ expect(subject.github_url).to be(nil)
262
+ end
263
+ end
264
+ end
265
+
266
+ describe "#gitlab_url" do
267
+ context "when #gitlab is set" do
268
+ subject { described_class.new(name, gitlab: gitlab) }
269
+
270
+ it "must return the 'https://gitlab.com/...' URL" do
271
+ expect(subject.gitlab_url).to eq("https://gitlab.com/#{gitlab}")
272
+ end
273
+
274
+ context "but the twitter handle starts with a '@'" do
275
+ subject { described_class.new(name, gitlab: "@#{gitlab}") }
276
+
277
+ it "must omit the leading '@' character" do
278
+ expect(subject.gitlab_url).to eq("https://gitlab.com/#{gitlab}")
279
+ end
280
+ end
281
+ end
282
+
283
+ context "when #gitlab is not set" do
284
+ subject { described_class.new(name) }
285
+
286
+ it "must return nil" do
287
+ expect(subject.gitlab_url).to be(nil)
288
+ end
289
+ end
290
+ end
291
+
292
+ describe "#twitter_url" do
293
+ context "when #twitter is set" do
294
+ subject { described_class.new(name, twitter: twitter) }
295
+
296
+ it "must return the 'https://twitter.com/...' URL" do
297
+ expect(subject.twitter_url).to eq("https://twitter.com/#{twitter}")
298
+ end
299
+
300
+ context "but the twitter handle starts with a '@'" do
301
+ subject { described_class.new(name, twitter: "@#{twitter}") }
302
+
303
+ it "must omit the leading '@' character" do
304
+ expect(subject.twitter_url).to eq("https://twitter.com/#{twitter}")
305
+ end
306
+ end
307
+ end
308
+
309
+ context "when #twitter is not set" do
310
+ subject { described_class.new(name) }
311
+
312
+ it "must return nil" do
313
+ expect(subject.twitter_url).to be(nil)
314
+ end
315
+ end
316
+ end
317
+
318
+ describe "#to_s" do
319
+ context "when #name and #email are set" do
320
+ subject { described_class.new(name, email: email) }
321
+
322
+ it "must return a formatted email address with the name" do
323
+ expect(subject.to_s).to eq("#{name} <#{email}>")
324
+ end
325
+ end
326
+
327
+ context "when only #name is set" do
328
+ subject { described_class.new(name) }
329
+
330
+ it "must return #name" do
331
+ expect(subject.to_s).to eq(name)
332
+ end
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/metadata/authors'
3
+
4
+ describe Ronin::Core::Metadata::Authors do
5
+ module TestMetadataAuthor
6
+ class WithNoAuthors
7
+ include Ronin::Core::Metadata::Authors
8
+ end
9
+
10
+ class WithOneAuthor
11
+ include Ronin::Core::Metadata::Authors
12
+
13
+ author 'John Doe'
14
+ end
15
+
16
+ class InheritesAuthors < WithOneAuthor
17
+ end
18
+
19
+ class InheritesAndAddsAuthors < WithOneAuthor
20
+ author 'John Smith'
21
+ end
22
+
23
+ class WitthMultipleAuthors
24
+ include Ronin::Core::Metadata::Authors
25
+
26
+ author 'John Doe'
27
+ author 'John Smith'
28
+ end
29
+ end
30
+
31
+ describe ".authors" do
32
+ subject { test_class }
33
+
34
+ context "with there are no authors" do
35
+ let(:test_class) { TestMetadataAuthor::WithNoAuthors }
36
+
37
+ it "must default to []" do
38
+ expect(subject.authors).to eq([])
39
+ end
40
+ end
41
+
42
+ context "with at least one author" do
43
+ let(:test_class) { TestMetadataAuthor::WithOneAuthor }
44
+
45
+ it "must contain #{described_class::Author} objects" do
46
+ expect(subject.authors).to all(be_kind_of(described_class::Author))
47
+ end
48
+ end
49
+
50
+ context "when the super-class defines it's own authors" do
51
+ let(:test_class) { TestMetadataAuthor::InheritesAuthors }
52
+ let(:super_class) { test_class.superclass }
53
+
54
+ it "must inherit the authors from the super-class" do
55
+ expect(subject.authors).to eq(super_class.authors)
56
+ end
57
+
58
+ context "but the sub-class defines additional authors" do
59
+ let(:test_class) { TestMetadataAuthor::InheritesAndAddsAuthors }
60
+
61
+ it "must combine the sub-classes authors with the super-classes" do
62
+ expect(subject.authors).to include(*super_class.authors)
63
+ end
64
+
65
+ it "must not modify the superclasses authors" do
66
+ expect(super_class.authors).to_not contain_exactly(*subject.authors)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ describe ".author" do
73
+ subject { test_class }
74
+
75
+ context "when called with just a name" do
76
+ module TestMetadataAuthor
77
+ class AuthorWithOnlyName
78
+ include Ronin::Core::Metadata::Authors
79
+
80
+ author 'John Doe'
81
+ end
82
+ end
83
+
84
+ let(:test_class) { TestMetadataAuthor::AuthorWithOnlyName }
85
+ let(:author) { subject.authors.last }
86
+
87
+ it "must initialize the #{described_class::Author} object with that name and add it to .authors" do
88
+ expect(author).to be_kind_of(described_class::Author)
89
+ expect(author.name).to eq('John Doe')
90
+ end
91
+ end
92
+
93
+ context "when additional keyword arguments are given" do
94
+ module TestMetadataAuthor
95
+ class AuthorsWithContactInfo
96
+ include Ronin::Core::Metadata::Authors
97
+
98
+ author 'John Smith', email: 'john.smith@example.com',
99
+ pgp: '0x123456789',
100
+ website: 'https://jsmith.name',
101
+ blog: 'https://jsmith.name/blog',
102
+ github: 'jsmith1',
103
+ gitlab: 'jsmith2',
104
+ twitter: 'jsmith3',
105
+ discord: 'jsmith4'
106
+ end
107
+ end
108
+
109
+ let(:test_class) { TestMetadataAuthor::AuthorsWithContactInfo }
110
+ let(:author) { subject.authors.last }
111
+
112
+ it "must initialize #{described_class}::Author with those keywords and add it to .authors" do
113
+ expect(author).to be_kind_of(described_class::Author)
114
+ expect(author.name).to eq('John Smith')
115
+ expect(author.email).to eq('john.smith@example.com')
116
+ expect(author.pgp).to eq('0x123456789')
117
+ expect(author.website).to eq('https://jsmith.name')
118
+ expect(author.blog).to eq('https://jsmith.name/blog')
119
+ expect(author.github).to eq('jsmith1')
120
+ expect(author.gitlab).to eq('jsmith2')
121
+ expect(author.twitter).to eq('jsmith3')
122
+ expect(author.discord).to eq('jsmith4')
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/metadata/description'
3
+
4
+ describe Ronin::Core::Metadata::Description do
5
+ describe ".description" do
6
+ subject { test_class }
7
+
8
+ context "and when description is not set in the class" do
9
+ module TestMetadataDescription
10
+ class WithNoDescriptionSet
11
+ include Ronin::Core::Metadata::Description
12
+ end
13
+ end
14
+
15
+ let(:test_class) { TestMetadataDescription::WithNoDescriptionSet }
16
+
17
+ it "must default to nil" do
18
+ expect(subject.description).to be(nil)
19
+ end
20
+ end
21
+
22
+ context "and when description is set in the class" do
23
+ module TestMetadataDescription
24
+ class WithDescriptionSet
25
+ include Ronin::Core::Metadata::Description
26
+
27
+ description 'test'
28
+ end
29
+ end
30
+
31
+ let(:test_class) { TestMetadataDescription::WithDescriptionSet }
32
+
33
+ it "must return the set description" do
34
+ expect(subject.description).to eq("test")
35
+ end
36
+ end
37
+
38
+ context "but when the description was set in the superclass" do
39
+ module TestMetadataDescription
40
+ class InheritsItsDescription < WithDescriptionSet
41
+ include Ronin::Core::Metadata::Description
42
+ end
43
+ end
44
+
45
+ let(:test_class) { TestMetadataDescription::InheritsItsDescription }
46
+
47
+ it "must return the description set in the superclass" do
48
+ expect(subject.description).to eq("test")
49
+ end
50
+
51
+ context "but the description is overridden in the sub-class" do
52
+ module TestMetadataDescription
53
+ class OverridesItsInheritedDescription < WithDescriptionSet
54
+ include Ronin::Core::Metadata::Description
55
+
56
+ description "test2"
57
+ end
58
+ end
59
+
60
+ let(:test_class) do
61
+ TestMetadataDescription::OverridesItsInheritedDescription
62
+ end
63
+
64
+ it "must return the description set in the sub-class" do
65
+ expect(subject.description).to eq("test2")
66
+ end
67
+
68
+ it "must not modify the superclass'es description" do
69
+ expect(subject.superclass.description).to eq('test')
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/metadata/id'
3
+
4
+ describe Ronin::Core::Metadata::ID do
5
+ module TestMetadataID
6
+ class WithNoIDSet
7
+ include Ronin::Core::Metadata::ID
8
+ end
9
+
10
+ class WithIDSet
11
+ include Ronin::Core::Metadata::ID
12
+
13
+ id 'test'
14
+ end
15
+ end
16
+
17
+ describe ".id" do
18
+ subject { test_class }
19
+
20
+ context "and when id is not set in the class" do
21
+ let(:test_class) { TestMetadataID::WithNoIDSet }
22
+
23
+ it "must default to nil" do
24
+ expect(subject.id).to be(nil)
25
+ end
26
+ end
27
+
28
+ context "and when id is set in the class" do
29
+ let(:test_class) { TestMetadataID::WithIDSet }
30
+
31
+ it "must return the set id" do
32
+ expect(subject.id).to eq("test")
33
+ end
34
+ end
35
+
36
+ context "but when the id was set in the superclass" do
37
+ module TestMetadataID
38
+ class InheritsItsID < WithIDSet
39
+ include Ronin::Core::Metadata::ID
40
+ end
41
+ end
42
+
43
+ let(:test_class) { TestMetadataID::InheritsItsID }
44
+
45
+ it "must return nil" do
46
+ expect(subject.id).to be(nil)
47
+ end
48
+
49
+ context "but the id is overridden in the sub-class" do
50
+ module TestMetadataID
51
+ class OverridesItsInheritedID < WithIDSet
52
+ include Ronin::Core::Metadata::ID
53
+
54
+ id "test2"
55
+ end
56
+ end
57
+
58
+ let(:test_class) do
59
+ TestMetadataID::OverridesItsInheritedID
60
+ end
61
+
62
+ it "must return the id set in the sub-class" do
63
+ expect(subject.id).to eq("test2")
64
+ end
65
+
66
+ it "must not modify the superclass'es id" do
67
+ expect(subject.superclass.id).to eq('test')
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#class_id" do
74
+ subject { test_class.new }
75
+
76
+ context "when the class'es .id is not set" do
77
+ let(:test_class) { TestMetadataID::WithNoIDSet }
78
+
79
+ it "must return nil" do
80
+ expect(subject.class_id).to be(nil)
81
+ end
82
+ end
83
+
84
+ context "when the class'es .id is set" do
85
+ let(:test_class) { TestMetadataID::WithIDSet }
86
+
87
+ it "must return the .id" do
88
+ expect(subject.class_id).to eq(test_class.id)
89
+ end
90
+ end
91
+ end
92
+ end