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,16 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/command'
3
+
4
+ describe Ronin::Core::CLI::Command do
5
+ it "must inherit from CommandKit::Command" do
6
+ expect(described_class).to be < CommandKit::Command
7
+ end
8
+
9
+ it "must include CommandKit::Help::Man" do
10
+ expect(described_class).to include(CommandKit::Help::Man)
11
+ end
12
+
13
+ it "must include CommandKit::BugReport" do
14
+ expect(described_class).to include(CommandKit::BugReport)
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+
5
+ $LOAD_PATH.unshift(File.expand_path(File.join(__dir__,'..','..','..','lib')))
6
+ require 'ronin/core/cli/ruby_shell'
7
+
8
+ Ronin::Core::CLI::RubyShell.start
@@ -0,0 +1 @@
1
+ test1
@@ -0,0 +1 @@
1
+ test2
@@ -0,0 +1 @@
1
+ 1 + 1 = <%= 1 + 1 -%>
@@ -0,0 +1 @@
1
+ test
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/generator/options/author'
3
+ require 'ronin/core/cli/command'
4
+ require 'ronin/core/cli/generator'
5
+
6
+ describe Ronin::Core::CLI::Generator::Options::Author do
7
+ module TestAuthorOption
8
+ class TestCommand < Ronin::Core::CLI::Command
9
+ include Ronin::Core::CLI::Generator
10
+ include Ronin::Core::CLI::Generator::Options::Author
11
+
12
+ template_dir 'test'
13
+ end
14
+ end
15
+
16
+ let(:command_class) { TestAuthorOption::TestCommand }
17
+ subject { command_class.new }
18
+
19
+ let(:name) { 'Foo Bar' }
20
+ let(:email) { 'foo.bar@example.com' }
21
+
22
+ describe ".defaultor_name" do
23
+ subject { described_class }
24
+
25
+ context "when `git config user.name` is set" do
26
+ before { allow(Ronin::Core::Git).to receive(:user_name).and_return(name) }
27
+
28
+ it "must use `git config user.name`" do
29
+ expect(subject.default_name).to eq(name)
30
+ end
31
+ end
32
+
33
+ context "when `git config user.name` isn't set" do
34
+ before { allow(Ronin::Core::Git).to receive(:user_name).and_return(nil) }
35
+
36
+ it "must fallback to using the USERNAME environment variable" do
37
+ expect(subject.default_name).to eq(ENV['USERNAME'])
38
+ end
39
+ end
40
+ end
41
+
42
+ describe ".default_email" do
43
+ subject { described_class }
44
+
45
+ before { allow(Ronin::Core::Git).to receive(:user_email).and_return(email) }
46
+
47
+ it "must use `git config user.email`" do
48
+ expect(subject.default_email).to eq(email)
49
+ end
50
+ end
51
+
52
+ describe ".included" do
53
+ subject { command_class }
54
+
55
+ it "must add a '-a,--author NAME' option" do
56
+ expect(subject.options[:author]).to_not be_nil
57
+ expect(subject.options[:author].short).to eq('-a')
58
+ expect(subject.options[:author].value).to_not be_nil
59
+ expect(subject.options[:author].value.default.call).to eq(described_class.default_name)
60
+ expect(subject.options[:author].value.type).to eq(String)
61
+ expect(subject.options[:author].value.usage).to eq('NAME')
62
+
63
+ if (default_name = described_class.default_name)
64
+ expect(subject.options[:author].desc).to eq("The name of the author (Default: #{default_name})")
65
+ else
66
+ expect(subject.options[:author].desc).to eq("The name of the author")
67
+ end
68
+
69
+ expect(subject.options[:author].block).to_not be_nil
70
+ end
71
+
72
+ it "must add a '-e,--author-email EMAIL' option" do
73
+ expect(subject.options[:author_email]).to_not be_nil
74
+ expect(subject.options[:author_email].short).to eq('-e')
75
+ expect(subject.options[:author_email].value).to_not be_nil
76
+ expect(subject.options[:author_email].value.default.call).to eq(described_class.default_email)
77
+ expect(subject.options[:author_email].value.type).to eq(String)
78
+ expect(subject.options[:author_email].value.usage).to eq('EMAIL')
79
+
80
+ if (default_email = described_class.default_email)
81
+ expect(subject.options[:author_email].desc).to eq("The email address of the author (Default: #{default_email})")
82
+ else
83
+ expect(subject.options[:author_email].desc).to eq("The email address of the author")
84
+ end
85
+
86
+ expect(subject.options[:author_email].block).to_not be_nil
87
+ end
88
+ end
89
+
90
+ describe "#initialize" do
91
+ it "must set #author_name to #{described_class}.default_name" do
92
+ expect(subject.author_name).to eq(described_class.default_name)
93
+ end
94
+
95
+ it "must set #author_email to #{described_class}.default_email" do
96
+ expect(subject.author_email).to eq(described_class.default_email)
97
+ end
98
+ end
99
+
100
+ describe "#parse_options" do
101
+ context "when given '--author NAME'" do
102
+ let(:argv) { ['--author', name] }
103
+
104
+ before { subject.parse_options(argv) }
105
+
106
+ it "must set #uathor_name" do
107
+ expect(subject.author_name).to eq(name)
108
+ end
109
+ end
110
+
111
+ context "when given '--author-email NAME'" do
112
+ let(:argv) { ['--author-email', email] }
113
+
114
+ before { subject.parse_options(argv) }
115
+
116
+ it "must set #uathor_email" do
117
+ expect(subject.author_email).to eq(email)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/generator/options/description'
3
+ require 'ronin/core/cli/command'
4
+ require 'ronin/core/cli/generator'
5
+
6
+ describe Ronin::Core::CLI::Generator::Options::Description do
7
+ module TestDescriptionOption
8
+ class TestCommand < Ronin::Core::CLI::Command
9
+ include Ronin::Core::CLI::Generator
10
+ include Ronin::Core::CLI::Generator::Options::Description
11
+
12
+ template_dir 'test'
13
+ end
14
+ end
15
+
16
+ let(:command_class) { TestDescriptionOption::TestCommand }
17
+ subject { command_class.new }
18
+
19
+ let(:description) { 'Foo bar baz' }
20
+
21
+ describe ".included" do
22
+ subject { command_class }
23
+
24
+ it "must add a '-D,--description TEXT' option" do
25
+ expect(subject.options[:description]).to_not be_nil
26
+ expect(subject.options[:description].short).to eq('-D')
27
+ expect(subject.options[:description].value).to_not be_nil
28
+ expect(subject.options[:description].value.type).to eq(String)
29
+ expect(subject.options[:description].value.usage).to eq('TEXT')
30
+ expect(subject.options[:description].desc).to eq('A longer description')
31
+ end
32
+ end
33
+
34
+ describe "#parse_options" do
35
+ context "when given '--description TEXT'" do
36
+ let(:argv) { ['--description', description] }
37
+
38
+ before { subject.parse_options(argv) }
39
+
40
+ it "must set #description" do
41
+ expect(subject.description).to eq(description)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/generator/options/reference'
3
+ require 'ronin/core/cli/command'
4
+ require 'ronin/core/cli/generator'
5
+
6
+ describe Ronin::Core::CLI::Generator::Options::Reference do
7
+ module TestReferenceOption
8
+ class TestCommand < Ronin::Core::CLI::Command
9
+ include Ronin::Core::CLI::Generator
10
+ include Ronin::Core::CLI::Generator::Options::Reference
11
+
12
+ template_dir 'test'
13
+ end
14
+ end
15
+
16
+ let(:command_class) { TestReferenceOption::TestCommand }
17
+ subject { command_class.new }
18
+
19
+ let(:url1) { 'https://example.com/link1' }
20
+ let(:url2) { 'https://example.com/link2' }
21
+
22
+ describe ".included" do
23
+ subject { command_class }
24
+
25
+ it "must add a '-R,--reference URL' option" do
26
+ expect(subject.options[:reference]).to_not be_nil
27
+ expect(subject.options[:reference].short).to eq('-R')
28
+ expect(subject.options[:reference].value).to_not be_nil
29
+ expect(subject.options[:reference].value.type).to eq(String)
30
+ expect(subject.options[:reference].value.usage).to eq('URL')
31
+ expect(subject.options[:reference].desc).to eq('Adds a reference URL')
32
+ expect(subject.options[:reference].block).to_not be_nil
33
+ end
34
+ end
35
+
36
+ describe "#initialize" do
37
+ it "must initialize #references to an empty Array" do
38
+ expect(subject.references).to eq([])
39
+ end
40
+ end
41
+
42
+ describe "#parse_options" do
43
+ context "when given '--reference URL'" do
44
+ let(:argv) { ['--reference', url1, '--reference', url2] }
45
+
46
+ before { subject.parse_options(argv) }
47
+
48
+ it "must append the URLs to #references" do
49
+ expect(subject.references).to eq([url1, url2])
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/generator/options/summary'
3
+ require 'ronin/core/cli/command'
4
+ require 'ronin/core/cli/generator'
5
+
6
+ describe Ronin::Core::CLI::Generator::Options::Summary do
7
+ module TestSummaryOption
8
+ class TestCommand < Ronin::Core::CLI::Command
9
+ include Ronin::Core::CLI::Generator
10
+ include Ronin::Core::CLI::Generator::Options::Summary
11
+
12
+ template_dir 'test'
13
+ end
14
+ end
15
+
16
+ let(:command_class) { TestSummaryOption::TestCommand }
17
+ subject { command_class.new }
18
+
19
+ let(:summary) { 'Foo bar baz' }
20
+
21
+ describe ".included" do
22
+ subject { command_class }
23
+
24
+ it "must add a '-S,--summary TEXT' option" do
25
+ expect(subject.options[:summary]).to_not be_nil
26
+ expect(subject.options[:summary].short).to eq('-S')
27
+ expect(subject.options[:summary].value).to_not be_nil
28
+ expect(subject.options[:summary].value.type).to eq(String)
29
+ expect(subject.options[:summary].value.usage).to eq('TEXT')
30
+ expect(subject.options[:summary].desc).to eq('One sentence summary')
31
+ end
32
+ end
33
+
34
+ describe "#parse_options" do
35
+ context "when given '--summary TEXT'" do
36
+ let(:argv) { ['--summary', summary] }
37
+
38
+ before { subject.parse_options(argv) }
39
+
40
+ it "must set #summary" do
41
+ expect(subject.summary).to eq(summary)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,244 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/generator'
3
+
4
+ describe Ronin::Core::CLI::Generator do
5
+ module TestGenerator
6
+ class WithoutTemplateDir < Ronin::Core::CLI::Command
7
+ include Ronin::Core::CLI::Generator
8
+ end
9
+
10
+ class WithTemplateDir < Ronin::Core::CLI::Command
11
+
12
+ include Ronin::Core::CLI::Generator
13
+
14
+ template_dir File.join(__dir__,'fixtures','template')
15
+
16
+ end
17
+
18
+ class InheritedTemplateDir < WithTemplateDir
19
+ end
20
+ end
21
+
22
+ let(:command_class) { TestGenerator::WithTemplateDir }
23
+ subject { command_class.new }
24
+
25
+ describe ".template_dir" do
26
+ context "when called without arguments" do
27
+ context "and the .template_dir has been perviously defined" do
28
+ let(:command_class) { TestGenerator::WithTemplateDir }
29
+
30
+ it "must set the previously set template_dir" do
31
+ expect(command_class.template_dir).to eq(File.join(__dir__,'fixtures','template'))
32
+ end
33
+ end
34
+
35
+ context "but the .template_dir has been defined in the superclass" do
36
+ let(:command_superclass) { TestGenerator::WithTemplateDir }
37
+ let(:command_class) { TestGenerator::InheritedTemplateDir }
38
+
39
+ it "must return the template_dir set in the superclass" do
40
+ expect(command_class.template_dir).to eq(command_superclass.template_dir)
41
+ end
42
+ end
43
+
44
+ context "but the template_dir has not been defined" do
45
+ let(:command_class) { TestGenerator::WithoutTemplateDir }
46
+
47
+ it "must return nil" do
48
+ expect(command_class.template_dir).to be(nil)
49
+ end
50
+ end
51
+ end
52
+
53
+ context "when called with a String" do
54
+ let(:command_class) { TestGenerator::WithTemplateDir }
55
+
56
+ it "must set the template_dir" do
57
+ expect(command_class.template_dir).to eq(File.join(__dir__,'fixtures','template'))
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#initialize" do
63
+ context "when the template_dir has been previously defined" do
64
+ it "must set #template_dir to the class'es .template_dir" do
65
+ expect(subject.template_dir).to eq(command_class.template_dir)
66
+ end
67
+ end
68
+
69
+ context "when the template_dir has not been previously defined" do
70
+ let(:command_class) { TestGenerator::WithoutTemplateDir }
71
+
72
+ it do
73
+ expect {
74
+ command_class.new
75
+ }.to raise_error(NotImplementedError,"#{command_class} did not define template_dir")
76
+ end
77
+ end
78
+ end
79
+
80
+ describe "#print_action" do
81
+ let(:stdout) { StringIO.new }
82
+
83
+ subject { command_class.new(stdout: stdout) }
84
+
85
+ context "when two arguments are given" do
86
+ let(:command) { 'touch' }
87
+ let(:dest) { 'path/to/file' }
88
+
89
+ context "and STDOUT is a TTY" do
90
+ let(:ansi) { CommandKit::Colors::ANSI }
91
+
92
+ before do
93
+ allow(stdout).to receive(:tty?).and_return(true)
94
+ end
95
+
96
+ it "must output the command and dest highlighted in bold green" do
97
+ expect(stdout).to receive(:puts).with("\t#{ansi.bold(ansi.green(command))}\t#{ansi.green(dest)}")
98
+
99
+ subject.print_action(command,dest)
100
+ end
101
+ end
102
+
103
+ context "but STDOUT is not a TTY" do
104
+ it "must output the command and dest path separated by tabs" do
105
+ expect(stdout).to receive(:puts).with("\t#{command}\t#{dest}")
106
+
107
+ subject.print_action(command,dest)
108
+ end
109
+ end
110
+ end
111
+
112
+ context "when three arguments are given" do
113
+ let(:command) { 'cp -r' }
114
+ let(:source) { 'dir' }
115
+ let(:dest) { 'path/to/file' }
116
+
117
+ context "and STDOUT is a TTY" do
118
+ let(:ansi) { CommandKit::Colors::ANSI }
119
+
120
+ before do
121
+ allow(stdout).to receive(:tty?).and_return(true)
122
+ end
123
+
124
+ it "must output the command, source, and dest highlighted in bold green" do
125
+ expect(stdout).to receive(:puts).with("\t#{ansi.bold(ansi.green(command))}\t#{ansi.green(source)}\t#{ansi.green(dest)}")
126
+
127
+ subject.print_action(command,source,dest)
128
+ end
129
+ end
130
+
131
+ context "but STDOUT is not a TTY" do
132
+ it "must output the command, source, and dest path separated by tabs" do
133
+ expect(stdout).to receive(:puts).with("\t#{command}\t#{source}\t#{dest}")
134
+
135
+ subject.print_action(command,source,dest)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "#mkdir" do
142
+ let(:dest) { 'path/to/new_dir' }
143
+
144
+ it "must call #print_action and call FileUtils.mkdir_p" do
145
+ expect(subject).to receive(:print_action).with('mkdir',dest)
146
+ expect(FileUtils).to receive(:mkdir_p).with(dest)
147
+
148
+ subject.mkdir(dest)
149
+ end
150
+ end
151
+
152
+ describe "#touch" do
153
+ let(:dest) { 'path/to/new_file' }
154
+
155
+ it "must call #print_action and call FileUtils.touch" do
156
+ expect(subject).to receive(:print_action).with('touch',dest)
157
+ expect(FileUtils).to receive(:touch).with(dest)
158
+
159
+ subject.touch(dest)
160
+ end
161
+ end
162
+
163
+ describe "#chmod" do
164
+ let(:dest) { 'path/to/new_file' }
165
+ let(:mode) { "+x" }
166
+
167
+ it "must call #print_action and call FileUtils.chmod" do
168
+ expect(subject).to receive(:print_action).with("chmod",dest)
169
+ expect(FileUtils).to receive(:chmod).with(mode,dest)
170
+
171
+ subject.chmod(mode,dest)
172
+ end
173
+ end
174
+
175
+ describe "#cp" do
176
+ let(:source) { 'file.txt' }
177
+ let(:dest) { 'path/to/root' }
178
+
179
+ it "must call #print_action and call FileUtils.cp" do
180
+ expect(subject).to receive(:print_action).with('cp',source,dest)
181
+ expect(FileUtils).to receive(:cp).with(
182
+ File.join(subject.template_dir,source), dest
183
+ )
184
+
185
+ subject.cp(source,dest)
186
+ end
187
+ end
188
+
189
+ describe "#cp_r" do
190
+ let(:source) { 'dir' }
191
+ let(:dest) { 'path/to/root' }
192
+
193
+ it "must call #print_action and call FileUtils.cp_r" do
194
+ expect(subject).to receive(:print_action).with('cp -r',source,dest)
195
+ expect(FileUtils).to receive(:cp_r).with(
196
+ File.join(subject.template_dir,source), dest
197
+ )
198
+
199
+ subject.cp_r(source,dest)
200
+ end
201
+ end
202
+
203
+ describe "#erb" do
204
+ let(:source) { 'file.erb' }
205
+ let(:dest) { 'path/to/new_file.txt' }
206
+
207
+ it "must call #print_action, render the ERB, and call File.write" do
208
+ expect(subject).to receive(:print_action).with('erb',source,dest)
209
+ expect(File).to receive(:write).with(
210
+ dest, "1 + 1 = 2"
211
+ )
212
+
213
+ subject.erb(source,dest)
214
+ end
215
+
216
+ context "when no destination path is given" do
217
+ it "must not call #print_action, but return the rendered result" do
218
+ expect(subject).to_not receive(:print_action).with('erb',source,dest)
219
+ expect(File).to_not receive(:write).with(
220
+ dest, "1 + 1 = 2"
221
+ )
222
+
223
+ expect(subject.erb(source)).to eq("1 + 1 = 2")
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "#sh" do
229
+ let(:status) { double(:exit_status) }
230
+
231
+ let(:command) { 'cmd' }
232
+ let(:args) { %w[-a -b foo] }
233
+
234
+ it "must call #print_action and run the command" do
235
+ expect(subject).to receive(:print_action).with(
236
+ 'run', [command,*args].join(' ')
237
+ )
238
+
239
+ expect(subject).to receive(:system).with(command,*args).and_return(status)
240
+
241
+ expect(subject.sh(command,*args)).to be(status)
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+ require 'ronin/core/cli/logging'
3
+ require 'ronin/core/cli/command'
4
+ require 'stringio'
5
+
6
+ describe Ronin::Core::CLI::Logging do
7
+ module TestLogging
8
+ class TestCommand < Ronin::Core::CLI::Command
9
+
10
+ include Ronin::Core::CLI::Logging
11
+
12
+ end
13
+ end
14
+
15
+ let(:command_class) { TestLogging::TestCommand }
16
+ let(:stdout) { StringIO.new }
17
+ let(:stderr) { StringIO.new }
18
+ subject { command_class.new(stdout: stdout, stderr: stderr) }
19
+
20
+ let(:message) { "foo bar baz" }
21
+
22
+ let(:bright_green) { CommandKit::Colors::ANSI::BRIGHT_GREEN }
23
+ let(:bright_yellow) { CommandKit::Colors::ANSI::BRIGHT_YELLOW }
24
+ let(:bright_red) { CommandKit::Colors::ANSI::BRIGHT_RED }
25
+ let(:white) { CommandKit::Colors::ANSI::WHITE }
26
+ let(:bold) { CommandKit::Colors::ANSI::BOLD }
27
+ let(:reset_intensity) { CommandKit::Colors::ANSI::RESET_INTENSITY }
28
+ let(:reset_color) { CommandKit::Colors::ANSI::RESET_COLOR }
29
+
30
+ describe "#log_info" do
31
+ context "when stdout is a TTY" do
32
+ before { allow(stdout).to receive(:tty?).and_return(true) }
33
+
34
+ it "must print '>>> message' in bold-green and bold-white to stdout" do
35
+ subject.log_info(message)
36
+
37
+ expect(stdout.string).to eq(
38
+ "#{bold}#{bright_green}>>>#{reset_color}#{reset_intensity} #{bold}#{white}#{message}#{reset_color}#{reset_intensity}#{$/}"
39
+ )
40
+ end
41
+ end
42
+
43
+ context "when stdout is not a TTY" do
44
+ it "must print '>>> message' to stdout" do
45
+ subject.log_info(message)
46
+
47
+ expect(stdout.string).to eq(">>> #{message}#{$/}")
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#log_warn" do
53
+ context "when stdout is a TTY" do
54
+ before { allow(stdout).to receive(:tty?).and_return(true) }
55
+
56
+ it "must print '*** message' in bold-yellow and bold-white to stdout" do
57
+ subject.log_warn(message)
58
+
59
+ expect(stdout.string).to eq(
60
+ "#{bold}#{bright_yellow}***#{reset_color}#{reset_intensity} #{bold}#{white}#{message}#{reset_color}#{reset_intensity}#{$/}"
61
+ )
62
+ end
63
+ end
64
+
65
+ context "when stdout is not a TTY" do
66
+ it "must print '*** message' to stdout" do
67
+ subject.log_warn(message)
68
+
69
+ expect(stdout.string).to eq("*** #{message}#{$/}")
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#log_error" do
75
+ context "when stderr is a TTY" do
76
+ before { allow(stderr).to receive(:tty?).and_return(true) }
77
+
78
+ it "must print '!!! message' in bold-red and bold-white to stderr" do
79
+ subject.log_error(message)
80
+
81
+ expect(stderr.string).to eq(
82
+ "#{bold}#{bright_red}!!!#{reset_color}#{reset_intensity} #{bold}#{white}#{message}#{reset_color}#{reset_intensity}#{$/}"
83
+ )
84
+ end
85
+ end
86
+
87
+ context "when stdout is not a TTY" do
88
+ it "must print '!!! message' to stderr" do
89
+ subject.log_error(message)
90
+
91
+ expect(stderr.string).to eq("!!! #{message}#{$/}")
92
+ end
93
+ end
94
+ end
95
+ end