ronin-core 0.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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