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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +41 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.rubocop.yml +160 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +11 -0
- data/Gemfile +30 -0
- data/README.md +299 -0
- data/Rakefile +34 -0
- data/examples/ruby_shell.rb +11 -0
- data/gemspec.yml +28 -0
- data/lib/ronin/core/class_registry.rb +246 -0
- data/lib/ronin/core/cli/command.rb +87 -0
- data/lib/ronin/core/cli/command_shell/command.rb +110 -0
- data/lib/ronin/core/cli/command_shell.rb +345 -0
- data/lib/ronin/core/cli/generator/options/author.rb +106 -0
- data/lib/ronin/core/cli/generator/options/description.rb +54 -0
- data/lib/ronin/core/cli/generator/options/reference.rb +60 -0
- data/lib/ronin/core/cli/generator/options/summary.rb +54 -0
- data/lib/ronin/core/cli/generator.rb +238 -0
- data/lib/ronin/core/cli/logging.rb +59 -0
- data/lib/ronin/core/cli/options/param.rb +68 -0
- data/lib/ronin/core/cli/options/values/arches.rb +45 -0
- data/lib/ronin/core/cli/options/values/oses.rb +32 -0
- data/lib/ronin/core/cli/printing/arch.rb +71 -0
- data/lib/ronin/core/cli/printing/metadata.rb +113 -0
- data/lib/ronin/core/cli/printing/os.rb +54 -0
- data/lib/ronin/core/cli/printing/params.rb +69 -0
- data/lib/ronin/core/cli/ruby_shell.rb +131 -0
- data/lib/ronin/core/cli/shell.rb +186 -0
- data/lib/ronin/core/git.rb +73 -0
- data/lib/ronin/core/home.rb +86 -0
- data/lib/ronin/core/metadata/authors/author.rb +241 -0
- data/lib/ronin/core/metadata/authors.rb +120 -0
- data/lib/ronin/core/metadata/description.rb +100 -0
- data/lib/ronin/core/metadata/id.rb +88 -0
- data/lib/ronin/core/metadata/references.rb +87 -0
- data/lib/ronin/core/metadata/summary.rb +78 -0
- data/lib/ronin/core/metadata/version.rb +74 -0
- data/lib/ronin/core/params/exceptions.rb +38 -0
- data/lib/ronin/core/params/mixin.rb +317 -0
- data/lib/ronin/core/params/param.rb +137 -0
- data/lib/ronin/core/params/types/boolean.rb +64 -0
- data/lib/ronin/core/params/types/enum.rb +107 -0
- data/lib/ronin/core/params/types/float.rb +68 -0
- data/lib/ronin/core/params/types/integer.rb +100 -0
- data/lib/ronin/core/params/types/numeric.rb +106 -0
- data/lib/ronin/core/params/types/regexp.rb +67 -0
- data/lib/ronin/core/params/types/string.rb +118 -0
- data/lib/ronin/core/params/types/type.rb +54 -0
- data/lib/ronin/core/params/types/uri.rb +72 -0
- data/lib/ronin/core/params/types.rb +62 -0
- data/lib/ronin/core/params.rb +19 -0
- data/lib/ronin/core/version.rb +24 -0
- data/ronin-core.gemspec +59 -0
- data/spec/class_registry_spec.rb +224 -0
- data/spec/cli/command_shell/command_spec.rb +113 -0
- data/spec/cli/command_shell_spec.rb +1114 -0
- data/spec/cli/command_spec.rb +16 -0
- data/spec/cli/fixtures/irb_command +8 -0
- data/spec/cli/fixtures/template/dir/file1.txt +1 -0
- data/spec/cli/fixtures/template/dir/file2.txt +1 -0
- data/spec/cli/fixtures/template/file.erb +1 -0
- data/spec/cli/fixtures/template/file.txt +1 -0
- data/spec/cli/generator/options/author_spec.rb +121 -0
- data/spec/cli/generator/options/description_spec.rb +45 -0
- data/spec/cli/generator/options/reference_spec.rb +53 -0
- data/spec/cli/generator/options/summary_spec.rb +45 -0
- data/spec/cli/generator_spec.rb +244 -0
- data/spec/cli/logging_spec.rb +95 -0
- data/spec/cli/options/param_spec.rb +67 -0
- data/spec/cli/options/values/arches_spec.rb +62 -0
- data/spec/cli/printing/arch_spec.rb +130 -0
- data/spec/cli/printing/metadata_spec.rb +211 -0
- data/spec/cli/printing/os_spec.rb +64 -0
- data/spec/cli/printing/params_spec.rb +63 -0
- data/spec/cli/ruby_shell.rb +99 -0
- data/spec/cli/shell_spec.rb +211 -0
- data/spec/fixtures/example_class_registry/base_class.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/loaded_class.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/name_mismatch.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/no_module.rb +4 -0
- data/spec/fixtures/example_class_registry.rb +8 -0
- data/spec/git_spec.rb +58 -0
- data/spec/home_spec.rb +64 -0
- data/spec/metadata/authors/author_spec.rb +335 -0
- data/spec/metadata/authors_spec.rb +126 -0
- data/spec/metadata/description_spec.rb +74 -0
- data/spec/metadata/id_spec.rb +92 -0
- data/spec/metadata/references_spec.rb +100 -0
- data/spec/metadata/summary_spec.rb +74 -0
- data/spec/metadata/version_spec.rb +72 -0
- data/spec/params/mixin_spec.rb +484 -0
- data/spec/params/param_spec.rb +164 -0
- data/spec/params/types/boolean_spec.rb +56 -0
- data/spec/params/types/enum_spec.rb +94 -0
- data/spec/params/types/float_spec.rb +107 -0
- data/spec/params/types/integer_spec.rb +155 -0
- data/spec/params/types/numeric_spec.rb +138 -0
- data/spec/params/types/regexp_spec.rb +64 -0
- data/spec/params/types/string_spec.rb +174 -0
- data/spec/params/types/type_spec.rb +14 -0
- data/spec/params/types/uri_spec.rb +62 -0
- data/spec/spec_helper.rb +11 -0
- metadata +252 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
4
|
+
#
|
|
5
|
+
# ronin-core is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# ronin-core is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
require 'ronin/core/params/exceptions'
|
|
20
|
+
require 'ronin/core/params/types/string'
|
|
21
|
+
require 'ronin/core/params/types/boolean'
|
|
22
|
+
require 'ronin/core/params/types/integer'
|
|
23
|
+
require 'ronin/core/params/types/float'
|
|
24
|
+
require 'ronin/core/params/types/regexp'
|
|
25
|
+
require 'ronin/core/params/types/uri'
|
|
26
|
+
require 'ronin/core/params/types/enum'
|
|
27
|
+
|
|
28
|
+
module Ronin
|
|
29
|
+
module Core
|
|
30
|
+
module Params
|
|
31
|
+
module Types
|
|
32
|
+
# Mapping of ruby core classes to param types.
|
|
33
|
+
TYPE_ALIASES = {
|
|
34
|
+
::String => Types::String,
|
|
35
|
+
::Integer => Types::Integer,
|
|
36
|
+
::Float => Types::Float,
|
|
37
|
+
::Regexp => Types::Regexp,
|
|
38
|
+
::URI => Types::URI,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Looks up a type class.
|
|
43
|
+
#
|
|
44
|
+
# @param [Class] type_class
|
|
45
|
+
# The ruby class to map to a param type class.
|
|
46
|
+
#
|
|
47
|
+
# @return [Class<Types::Type>]
|
|
48
|
+
# The param type class.
|
|
49
|
+
#
|
|
50
|
+
def self.lookup(type_class)
|
|
51
|
+
if type_class < Type
|
|
52
|
+
type_class
|
|
53
|
+
else
|
|
54
|
+
TYPE_ALIASES.fetch(type_class) do
|
|
55
|
+
raise(UnknownType,"unknown param type: #{type_class.inspect}")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
4
|
+
#
|
|
5
|
+
# ronin-core is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# ronin-core is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
require 'ronin/core/params/mixin'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
4
|
+
#
|
|
5
|
+
# ronin-core is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published
|
|
7
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# ronin-core is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Ronin
|
|
20
|
+
module Core
|
|
21
|
+
# ronin-core version
|
|
22
|
+
VERSION = '0.1.0.beta1'
|
|
23
|
+
end
|
|
24
|
+
end
|
data/ronin-core.gemspec
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |gem|
|
|
4
|
+
gemspec = YAML.load_file('gemspec.yml')
|
|
5
|
+
|
|
6
|
+
gem.name = gemspec.fetch('name')
|
|
7
|
+
gem.version = gemspec.fetch('version') do
|
|
8
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
|
9
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
|
10
|
+
|
|
11
|
+
require 'ronin/core/version'
|
|
12
|
+
Ronin::Core::VERSION
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
gem.summary = gemspec['summary']
|
|
16
|
+
gem.description = gemspec['description']
|
|
17
|
+
gem.licenses = Array(gemspec['license'])
|
|
18
|
+
gem.authors = Array(gemspec['authors'])
|
|
19
|
+
gem.email = gemspec['email']
|
|
20
|
+
gem.homepage = gemspec['homepage']
|
|
21
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
|
22
|
+
|
|
23
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
|
24
|
+
|
|
25
|
+
gem.files = `git ls-files`.split($/)
|
|
26
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
|
27
|
+
gem.files += Array(gemspec['generated_files'])
|
|
28
|
+
|
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
|
34
|
+
gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
|
|
35
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
|
36
|
+
|
|
37
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
|
38
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
gem.requirements = gemspec['requirements']
|
|
42
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
|
43
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
|
44
|
+
gem.post_install_message = gemspec['post_install_message']
|
|
45
|
+
|
|
46
|
+
split = lambda { |string| string.split(/,\s*/) }
|
|
47
|
+
|
|
48
|
+
if gemspec['dependencies']
|
|
49
|
+
gemspec['dependencies'].each do |name,versions|
|
|
50
|
+
gem.add_dependency(name,split[versions])
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if gemspec['development_dependencies']
|
|
55
|
+
gemspec['development_dependencies'].each do |name,versions|
|
|
56
|
+
gem.add_development_dependency(name,split[versions])
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'ronin/core/class_registry'
|
|
3
|
+
|
|
4
|
+
require 'fixtures/example_class_registry'
|
|
5
|
+
|
|
6
|
+
describe Ronin::Core::ClassRegistry do
|
|
7
|
+
let(:fixtures_dir) { File.join(__dir__,'fixtures') }
|
|
8
|
+
|
|
9
|
+
describe ".class_dir" do
|
|
10
|
+
context "when a class_dir has been defined" do
|
|
11
|
+
module TestClassRegistry
|
|
12
|
+
module WithAModulesDir
|
|
13
|
+
include Ronin::Core::ClassRegistry
|
|
14
|
+
|
|
15
|
+
class_dir "#{__dir__}/test/dir"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject { TestClassRegistry::WithAModulesDir }
|
|
20
|
+
|
|
21
|
+
it "must return the previously set .class_dir" do
|
|
22
|
+
expect(subject.class_dir).to eq("#{__dir__}/test/dir")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "but when no class_dir has been defined" do
|
|
27
|
+
module TestClassRegistry
|
|
28
|
+
module WithNoModuleLoadPath
|
|
29
|
+
include Ronin::Core::ClassRegistry
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
subject { TestClassRegistry::WithNoModuleLoadPath }
|
|
34
|
+
|
|
35
|
+
it do
|
|
36
|
+
expect {
|
|
37
|
+
subject.class_dir
|
|
38
|
+
}.to raise_error(NotImplementedError,"#{subject} did not define a class_dir")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
subject { ExampleClassRegistry }
|
|
44
|
+
|
|
45
|
+
describe ".list_files" do
|
|
46
|
+
it "must return an Array of module names" do
|
|
47
|
+
expect(subject.list_files).to eq(
|
|
48
|
+
%w[
|
|
49
|
+
loaded_class
|
|
50
|
+
name_mismatch
|
|
51
|
+
no_module
|
|
52
|
+
]
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe ".registry" do
|
|
58
|
+
it "must default to {}" do
|
|
59
|
+
expect(subject.registry).to eq({})
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe ".path_for" do
|
|
64
|
+
context "when the module name exists within the .class_dir" do
|
|
65
|
+
let(:id) { 'loaded_class' }
|
|
66
|
+
|
|
67
|
+
it "must return the path to the .rb file for the module" do
|
|
68
|
+
expect(subject.path_for(id)).to eq(
|
|
69
|
+
File.join(subject.class_dir,"#{id}.rb")
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context "when the module name does not have a file within .class_dir" do
|
|
75
|
+
let(:id) { "does_not_exist" }
|
|
76
|
+
|
|
77
|
+
it "must return nil" do
|
|
78
|
+
expect(subject.path_for(id)).to be(nil)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe ".register" do
|
|
84
|
+
module TestClassRegistry
|
|
85
|
+
module ExampleNamespace
|
|
86
|
+
class Foo
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
let(:id) { 'foo' }
|
|
92
|
+
let(:klass) { TestClassRegistry::ExampleNamespace::Foo }
|
|
93
|
+
|
|
94
|
+
before { subject.register(id,klass) }
|
|
95
|
+
|
|
96
|
+
it "must add the class id and class to #registry" do
|
|
97
|
+
expect(subject.registry[id]).to be(klass)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
after { subject.registry.clear }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe ".load_class_from_file" do
|
|
104
|
+
let(:id) { 'loaded_class' }
|
|
105
|
+
let(:file) { File.join(subject.class_dir,"#{id}.rb") }
|
|
106
|
+
let(:klass) { ExampleClassRegistry::LoadedClass }
|
|
107
|
+
|
|
108
|
+
it "must require the file" do
|
|
109
|
+
subject.load_class_from_file(file)
|
|
110
|
+
|
|
111
|
+
expect($LOADED_FEATURES).to include(file)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "must return the registered module" do
|
|
115
|
+
expect(subject.load_class_from_file(file)).to be(klass)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must register the module with the same id as the file" do
|
|
119
|
+
subject.load_class_from_file(file)
|
|
120
|
+
|
|
121
|
+
expect(subject.registry[id]).to be(klass)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "when given a relative path" do
|
|
125
|
+
let(:relative_path) { File.join(subject.class_dir,'foo','..',"#{id}.rb") }
|
|
126
|
+
let(:absolute_path) { File.expand_path(relative_path) }
|
|
127
|
+
|
|
128
|
+
it "must expand the path first" do
|
|
129
|
+
expect(subject).to receive(:require).with(absolute_path) do
|
|
130
|
+
load(absolute_path)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
subject.load_class_from_file(relative_path)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "when the file does not exist" do
|
|
138
|
+
let(:file) { "path/does/not/exist.rb" }
|
|
139
|
+
let(:absolute_path) { File.expand_path(file) }
|
|
140
|
+
|
|
141
|
+
it do
|
|
142
|
+
expect {
|
|
143
|
+
subject.load_class_from_file(file)
|
|
144
|
+
}.to raise_error(described_class::ClassNotFound,"no such file or directory: #{absolute_path.inspect}")
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context "when the file does not register a module" do
|
|
149
|
+
let(:id) { 'no_module' }
|
|
150
|
+
let(:file) { File.join(subject.class_dir,"#{id}.rb") }
|
|
151
|
+
|
|
152
|
+
it do
|
|
153
|
+
expect {
|
|
154
|
+
subject.load_class_from_file(file)
|
|
155
|
+
}.to raise_error(described_class::ClassNotFound,"file did not register a class: #{file.inspect}")
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
after do
|
|
160
|
+
subject.registry.clear
|
|
161
|
+
$LOADED_FEATURES.delete(file)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe ".load_class" do
|
|
166
|
+
let(:id) { 'loaded_class' }
|
|
167
|
+
let(:klass) { ExampleClassRegistry::LoadedClass }
|
|
168
|
+
let(:path) { File.join(subject.class_dir,"#{id}.rb") }
|
|
169
|
+
|
|
170
|
+
it "must require the file within the .class_dir" do
|
|
171
|
+
subject.load_class(id)
|
|
172
|
+
|
|
173
|
+
expect($LOADED_FEATURES).to include(path)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "must return the registered module" do
|
|
177
|
+
expect(subject.load_class(id)).to be(klass)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "must register the module with the same id as the file" do
|
|
181
|
+
subject.load_class(id)
|
|
182
|
+
|
|
183
|
+
expect(subject.registry[id]).to be(klass)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
context "when the file does not exist" do
|
|
187
|
+
let(:id) { 'does_not_exist' }
|
|
188
|
+
|
|
189
|
+
it do
|
|
190
|
+
expect {
|
|
191
|
+
subject.load_class(id)
|
|
192
|
+
}.to raise_error(described_class::ClassNotFound,"could not find file for #{id.inspect}")
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
context "when the file does not register a module" do
|
|
197
|
+
let(:id) { 'no_module' }
|
|
198
|
+
|
|
199
|
+
it do
|
|
200
|
+
expect {
|
|
201
|
+
subject.load_class(id)
|
|
202
|
+
}.to raise_error(described_class::ClassNotFound,"file did not register a class: #{path.inspect}")
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context "when the file registers a module of a different name" do
|
|
207
|
+
let(:id) { 'name_mismatch' }
|
|
208
|
+
let(:unexpected_id) { 'different_name' }
|
|
209
|
+
|
|
210
|
+
it do
|
|
211
|
+
expect {
|
|
212
|
+
subject.load_class(id)
|
|
213
|
+
}.to raise_error(described_class::ClassNotFound,"file registered a class with a different id (#{unexpected_id.inspect}): #{path.inspect}")
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
after do
|
|
220
|
+
subject.registry.clear
|
|
221
|
+
$LOADED_FEATURES.delete(path)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'ronin/core/cli/command_shell/command'
|
|
3
|
+
|
|
4
|
+
describe Ronin::Core::CLI::CommandShell::Command do
|
|
5
|
+
let(:name) { :foo }
|
|
6
|
+
let(:usage) { 'ARG1 [ARG2]' }
|
|
7
|
+
let(:completions) { %w[arg1 arg2] }
|
|
8
|
+
let(:summary) { 'Foo bar baz' }
|
|
9
|
+
let(:help) do
|
|
10
|
+
[
|
|
11
|
+
"Foo bar baz",
|
|
12
|
+
"blah blah blah",
|
|
13
|
+
"",
|
|
14
|
+
" foo /bar",
|
|
15
|
+
""
|
|
16
|
+
].join($/)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject do
|
|
20
|
+
described_class.new(name, usage: usage,
|
|
21
|
+
completions: completions,
|
|
22
|
+
summary: summary,
|
|
23
|
+
help: help)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#initialize" do
|
|
27
|
+
subject { described_class.new(name, summary: summary) }
|
|
28
|
+
|
|
29
|
+
it "must set #name" do
|
|
30
|
+
expect(subject.name).to eq(name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "must default #method_name to name" do
|
|
34
|
+
expect(subject.method_name).to eq(name)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "must default #usage to nil" do
|
|
38
|
+
expect(subject.usage).to be(nil)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "must default #completions to nil" do
|
|
42
|
+
expect(subject.completions).to be(nil)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "must default #help to #summary" do
|
|
46
|
+
expect(subject.help).to eq(subject.summary)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "when the method_name: keyword is given" do
|
|
50
|
+
let(:method_name) { 'foo2' }
|
|
51
|
+
|
|
52
|
+
subject do
|
|
53
|
+
described_class.new(name, method_name: method_name,
|
|
54
|
+
summary: summary)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "must override #method_name" do
|
|
58
|
+
expect(subject.method_name).to eq(method_name)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "when the usage: keyword is given" do
|
|
63
|
+
subject do
|
|
64
|
+
described_class.new(name, usage: usage,
|
|
65
|
+
summary: summary)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "must set #usage" do
|
|
69
|
+
expect(subject.usage).to eq(usage)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when the completions: keyword is given" do
|
|
74
|
+
subject do
|
|
75
|
+
described_class.new(name, usage: usage,
|
|
76
|
+
summary: summary,
|
|
77
|
+
completions: completions)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "must set #completions" do
|
|
81
|
+
expect(subject.completions).to eq(completions)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when the help: keyword is given" do
|
|
86
|
+
subject do
|
|
87
|
+
described_class.new(name, usage: usage,
|
|
88
|
+
summary: summary,
|
|
89
|
+
help: help)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "must set #help" do
|
|
93
|
+
expect(subject.help).to eq(help)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "#to_s" do
|
|
99
|
+
context "when #usage is set" do
|
|
100
|
+
it "must return the #name and #usage string" do
|
|
101
|
+
expect(subject.to_s).to eq("#{name} #{usage}")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "when #usage is not set" do
|
|
106
|
+
subject { described_class.new(name, summary: summary) }
|
|
107
|
+
|
|
108
|
+
it "must return the #name as a String" do
|
|
109
|
+
expect(subject.to_s).to eq(name.to_s)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|