ruby-pwsh 0.10.2 → 0.11.0.rc.1

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.
@@ -0,0 +1,293 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pwsh::Util do
6
+ let(:snake_case_string) { 'this_is_a_string' }
7
+ let(:pascal_case_string) { 'ThisIsAString' }
8
+ let(:kebab_case_string) { 'this-is-a-string' }
9
+ let(:camel_case_string) { 'thisIsAString' }
10
+ let(:snake_case_hash_in_an_array) do
11
+ [
12
+ 'just a string',
13
+ {
14
+ some_key: 'a value'
15
+ },
16
+ 1,
17
+ {
18
+ another_key: {
19
+ nested_key: 1,
20
+ nested_array: [
21
+ 1,
22
+ 'another string',
23
+ { super_nested_key: 'value' }
24
+ ]
25
+ }
26
+ }
27
+ ]
28
+ end
29
+ let(:snake_case_hash) do
30
+ {
31
+ a: 1,
32
+ apple_butter: %w[a b c],
33
+ some_key_value: {
34
+ nested_key: 1,
35
+ another_nested_key: 2
36
+ }
37
+ }
38
+ end
39
+ let(:pascal_case_hash_in_an_array) do
40
+ [
41
+ 'just a string',
42
+ {
43
+ SomeKey: 'a value'
44
+ },
45
+ 1,
46
+ {
47
+ AnotherKey: {
48
+ NestedKey: 1,
49
+ NestedArray: [
50
+ 1,
51
+ 'another string',
52
+ { SuperNestedKey: 'value' }
53
+ ]
54
+ }
55
+ }
56
+ ]
57
+ end
58
+ let(:pascal_case_hash) do
59
+ {
60
+ A: 1,
61
+ AppleButter: %w[a b c],
62
+ SomeKeyValue: {
63
+ NestedKey: 1,
64
+ AnotherNestedKey: 2
65
+ }
66
+ }
67
+ end
68
+ let(:kebab_case_hash) do
69
+ {
70
+ a: 1,
71
+ 'apple-butter': %w[a b c],
72
+ 'some-key-value': {
73
+ 'nested-key': 1,
74
+ 'another-nested-key': 2
75
+ }
76
+ }
77
+ end
78
+ let(:camel_case_hash) do
79
+ {
80
+ a: 1,
81
+ appleButter: %w[a b c],
82
+ someKeyValue: {
83
+ nestedKey: 1,
84
+ anotherNestedKey: 2
85
+ }
86
+ }
87
+ end
88
+
89
+ describe '.invalid_directories?' do
90
+ let(:valid_path_a) { 'C:/some/folder' }
91
+ let(:valid_path_b) { 'C:/another/folder' }
92
+ let(:valid_paths) { 'C:/some/folder;C:/another/folder' }
93
+ let(:invalid_path) { 'C:/invalid/path' }
94
+ let(:mixed_paths) { 'C:/some/folder;C:/invalid/path;C:/another/folder' }
95
+ let(:empty_string) { '' }
96
+ let(:empty_members) { 'C:/some/folder;;C:/another/folder' }
97
+
98
+ it 'returns false if passed nil' do
99
+ expect(described_class.invalid_directories?(nil)).to be false
100
+ end
101
+
102
+ it 'returns false if passed an empty string' do
103
+ expect(described_class.invalid_directories?('')).to be false
104
+ end
105
+
106
+ it 'returns false if one valid path is provided' do
107
+ expect(described_class).to receive(:on_windows?).and_return(true)
108
+ expect(File).to receive(:directory?).with(valid_path_a).and_return(true)
109
+ expect(described_class.invalid_directories?(valid_path_a)).to be false
110
+ end
111
+
112
+ it 'returns false if a collection of valid paths is provided' do
113
+ expect(described_class).to receive(:on_windows?).and_return(true)
114
+ expect(File).to receive(:directory?).with(valid_path_a).and_return(true)
115
+ expect(File).to receive(:directory?).with(valid_path_b).and_return(true)
116
+ expect(described_class.invalid_directories?(valid_paths)).to be false
117
+ end
118
+
119
+ it 'returns true if there is only one path and it is invalid' do
120
+ expect(described_class).to receive(:on_windows?).and_return(true)
121
+ expect(File).to receive(:directory?).with(invalid_path).and_return(false)
122
+ expect(described_class.invalid_directories?(invalid_path)).to be true
123
+ end
124
+
125
+ it 'returns true if the collection has on valid and one invalid member' do
126
+ expect(described_class).to receive(:on_windows?).and_return(true)
127
+ expect(File).to receive(:directory?).with(valid_path_a).and_return(true)
128
+ expect(File).to receive(:directory?).with(valid_path_b).and_return(true)
129
+ expect(File).to receive(:directory?).with(invalid_path).and_return(false)
130
+ expect(described_class.invalid_directories?(mixed_paths)).to be true
131
+ end
132
+
133
+ it 'returns false if collection has empty members but other entries are valid' do
134
+ expect(described_class).to receive(:on_windows?).and_return(true)
135
+ expect(File).to receive(:directory?).with(valid_path_a).and_return(true)
136
+ expect(File).to receive(:directory?).with(valid_path_b).and_return(true)
137
+ allow(File).to receive(:directory?).with('')
138
+ expect(described_class.invalid_directories?(empty_members)).to be false
139
+ end
140
+ end
141
+
142
+ describe '.snake_case' do
143
+ it 'converts a string to snake_case' do
144
+ expect(described_class.snake_case(camel_case_string)).to eq snake_case_string
145
+ expect(described_class.snake_case(kebab_case_string)).to eq snake_case_string
146
+ expect(described_class.snake_case(pascal_case_string)).to eq snake_case_string
147
+ end
148
+ end
149
+
150
+ describe '.snake_case_hash_keys' do
151
+ it 'snake_cases the keys in a passed hash' do
152
+ expect(described_class.snake_case_hash_keys(camel_case_hash)).to eq snake_case_hash
153
+ expect(described_class.snake_case_hash_keys(kebab_case_hash)).to eq snake_case_hash
154
+ expect(described_class.snake_case_hash_keys(pascal_case_hash)).to eq snake_case_hash
155
+ expect(described_class.snake_case_hash_keys(pascal_case_hash_in_an_array)).to eq snake_case_hash_in_an_array
156
+ end
157
+ end
158
+
159
+ describe '.pascal_case' do
160
+ it 'converts a string to PascalCase' do
161
+ expect(described_class.pascal_case(camel_case_string)).to eq pascal_case_string
162
+ expect(described_class.pascal_case(kebab_case_string)).to eq pascal_case_string
163
+ expect(described_class.pascal_case(snake_case_string)).to eq pascal_case_string
164
+ end
165
+ end
166
+
167
+ describe '.pascal_case_hash_keys' do
168
+ it 'PascalCases the keys in a passed hash' do
169
+ expect(described_class.pascal_case_hash_keys(camel_case_hash)).to eq pascal_case_hash
170
+ expect(described_class.pascal_case_hash_keys(kebab_case_hash)).to eq pascal_case_hash
171
+ expect(described_class.pascal_case_hash_keys(snake_case_hash)).to eq pascal_case_hash
172
+ expect(described_class.pascal_case_hash_keys(snake_case_hash_in_an_array)).to eq pascal_case_hash_in_an_array
173
+ end
174
+ end
175
+
176
+ describe '.symbolize_hash_keys' do
177
+ let(:array_with_string_keys_in_hashes) do
178
+ [
179
+ 'just a string',
180
+ {
181
+ 'some_key' => 'a value'
182
+ },
183
+ 1,
184
+ {
185
+ 'another_key' => {
186
+ 'nested_key' => 1,
187
+ 'nested_array' => [
188
+ 1,
189
+ 'another string',
190
+ { 'super_nested_key' => 'value' }
191
+ ]
192
+ }
193
+ }
194
+ ]
195
+ end
196
+ let(:array_with_symbol_keys_in_hashes) do
197
+ [
198
+ 'just a string',
199
+ {
200
+ some_key: 'a value'
201
+ },
202
+ 1,
203
+ {
204
+ another_key: {
205
+ nested_key: 1,
206
+ nested_array: [
207
+ 1,
208
+ 'another string',
209
+ { super_nested_key: 'value' }
210
+ ]
211
+ }
212
+ }
213
+ ]
214
+ end
215
+
216
+ it 'converts all string hash keys into symbols' do
217
+ expect(described_class.symbolize_hash_keys(array_with_string_keys_in_hashes)).to eq array_with_symbol_keys_in_hashes
218
+ end
219
+ end
220
+
221
+ describe '.escape_quotes' do
222
+ it 'handles single quotes' do
223
+ expect(described_class.escape_quotes("The 'Cats' go 'meow'!")).to match(/The ''Cats'' go ''meow''!/)
224
+ end
225
+
226
+ it 'handles double single quotes' do
227
+ expect(described_class.escape_quotes("The ''Cats'' go 'meow'!")).to match(/The ''''Cats'''' go ''meow''!/)
228
+ end
229
+
230
+ it 'handles double quotes' do
231
+ expect(described_class.escape_quotes("The 'Cats' go \"meow\"!")).to match(/The ''Cats'' go "meow"!/)
232
+ end
233
+
234
+ it 'handles dollar signs' do
235
+ expect(described_class.escape_quotes('This should show $foo variable')).to match(/This should show \$foo variable/)
236
+ end
237
+ end
238
+
239
+ describe '.format_powershell_value' do
240
+ let(:ruby_array) { ['string', 1, :symbol, true] }
241
+ let(:powershell_array) { "@('string', 1, symbol, $true)" }
242
+ let(:ruby_hash) do
243
+ {
244
+ string: 'string',
245
+ number: 1,
246
+ symbol: :some_symbol,
247
+ boolean: true,
248
+ nested_hash: {
249
+ another_string: 'foo',
250
+ another_number: 2,
251
+ array: [1, 2, 3]
252
+ }
253
+ }
254
+ end
255
+ let(:powershell_hash) { "@{string = 'string'; number = 1; symbol = some_symbol; boolean = $true; nested_hash = @{another_string = 'foo'; another_number = 2; array = @(1, 2, 3)}}" }
256
+
257
+ it 'returns a symbol as a non-interpolated string' do
258
+ expect(described_class.format_powershell_value(:apple)).to eq('apple')
259
+ end
260
+
261
+ it 'returns a number as a non interpolated string' do
262
+ expect(described_class.format_powershell_value(101)).to eq('101')
263
+ expect(described_class.format_powershell_value(1.1)).to eq('1.1')
264
+ end
265
+
266
+ it 'returns boolean values as the appropriate PowerShell automatic variable' do
267
+ expect(described_class.format_powershell_value(true)).to eq('$true')
268
+ expect(described_class.format_powershell_value(:false)).to eq('$false') # rubocop:disable Lint/BooleanSymbol
269
+ end
270
+
271
+ it 'returns a string as an escaped string' do
272
+ expect(described_class.format_powershell_value('some string')).to eq("'some string'")
273
+ end
274
+
275
+ it 'returns an array as a string representing a PowerShell array' do
276
+ expect(described_class.format_powershell_value(ruby_array)).to eq(powershell_array)
277
+ end
278
+
279
+ it 'returns a hash as a string representing a PowerShell hash' do
280
+ expect(described_class.format_powershell_value(ruby_hash)).to eq(powershell_hash)
281
+ end
282
+
283
+ it 'raises an error if an unknown type is passed' do
284
+ expect { described_class.format_powershell_value(described_class) }.to raise_error(/unsupported type Module/)
285
+ end
286
+ end
287
+
288
+ describe '.custom_powershell_property' do
289
+ it 'returns a powershell hash with the name and expression keys' do
290
+ expect(described_class.custom_powershell_property('apple', '$_.SomeValue / 5')).to eq("@{Name = 'apple'; Expression = {$_.SomeValue / 5}}")
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pwsh do
6
+ it 'has a version number' do
7
+ expect(described_class::VERSION).not_to be_nil
8
+ expect(described_class::VERSION).to be_a(String)
9
+ end
10
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Pwsh::WindowsPowerShell do
6
+ describe '.version' do
7
+ context 'on non-Windows platforms', unless: Pwsh::Util.on_windows? do
8
+ it 'is not defined' do
9
+ expect(defined?(described_class.version)).to be_nil
10
+ end
11
+ end
12
+
13
+ context 'On Windows', if: Pwsh::Util.on_windows? do
14
+ context 'when Windows PowerShell version is greater than three' do
15
+ it 'detects a Windows PowerShell version' do
16
+ allow_any_instance_of(Win32::Registry).to receive(:[]).with('PowerShellVersion').and_return('5.0.10514.6')
17
+ expect(described_class.version).to eq('5.0.10514.6')
18
+ end
19
+
20
+ it 'calls the Windows PowerShell three registry path' do
21
+ reg_key = instance_double(bob)
22
+ allow(reg_key).to receive(:[]).with('PowerShellVersion').and_return('5.0.10514.6')
23
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine', Win32::Registry::KEY_READ | 0x100).and_yield(reg_key)
24
+
25
+ described_class.version
26
+ end
27
+
28
+ it 'does not call Windows PowerShell one registry path' do
29
+ reg_key = instance_double(bob)
30
+ allow(reg_key).to receive(:[]).with('PowerShellVersion').and_return('5.0.10514.6')
31
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine', Win32::Registry::KEY_READ | 0x100).and_yield(reg_key)
32
+ expect_any_instance_of(Win32::Registry).not_to receive(:open).with('SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine', Win32::Registry::KEY_READ | 0x100)
33
+
34
+ described_class.version
35
+ end
36
+ end
37
+
38
+ context 'when Windows PowerShell version is less than three' do
39
+ it 'detects a Windows PowerShell version' do
40
+ allow_any_instance_of(Win32::Registry).to receive(:[]).with('PowerShellVersion').and_return('2.0')
41
+
42
+ expect(described_class.version).to eq('2.0')
43
+ end
44
+
45
+ it 'calls the Windows PowerShell one registry path' do
46
+ reg_key = instance_double(bob)
47
+ allow(reg_key).to receive(:[]).with('PowerShellVersion').and_return('2.0')
48
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine',
49
+ Win32::Registry::KEY_READ | 0x100).and_yield(reg_key)
50
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine',
51
+ Win32::Registry::KEY_READ | 0x100).and_raise(Win32::Registry::Error.new(2), 'nope')
52
+
53
+ expect(described_class.version).to eq('2.0')
54
+ end
55
+ end
56
+
57
+ context 'when Windows PowerShell is not installed' do
58
+ it 'returns nil and not throw' do
59
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine',
60
+ Win32::Registry::KEY_READ | 0x100).and_raise(Win32::Registry::Error.new(2), 'nope')
61
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine',
62
+ Win32::Registry::KEY_READ | 0x100).and_raise(Win32::Registry::Error.new(2), 'nope')
63
+
64
+ expect(described_class.version).to be_nil
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '.compatible_version?' do
71
+ context 'on non-Windows platforms', unless: Pwsh::Util.on_windows? do
72
+ it 'returns false' do
73
+ expect(described_class.compatible_version?).to be(false)
74
+ end
75
+ end
76
+
77
+ context 'On Windows', if: Pwsh::Util.on_windows? do
78
+ context 'when the Windows PowerShell major version is nil' do
79
+ it 'returns false' do
80
+ expect(described_class).to receive(:version).and_return(nil)
81
+ expect(described_class.compatible_version?).to be(false)
82
+ end
83
+ end
84
+
85
+ context 'when the Windows PowerShell major version is less than two' do
86
+ it 'returns false' do
87
+ expect(described_class).to receive(:version).and_return('1.0')
88
+ expect(described_class.compatible_version?).to be(false)
89
+ end
90
+ end
91
+
92
+ context 'when the Windows PowerShell major version is two' do
93
+ it 'returns true if .NET 3.5 is installed' do
94
+ expect(described_class).to receive(:version).and_return('2.0')
95
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5', Win32::Registry::KEY_READ | 0x100).and_yield
96
+ expect(described_class.compatible_version?).to be(true)
97
+ end
98
+
99
+ it 'returns false if .NET 3.5 is not installed' do
100
+ expect(described_class).to receive(:version).and_return('2.0')
101
+ allow_any_instance_of(Win32::Registry).to receive(:open).with('SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5', Win32::Registry::KEY_READ | 0x100).and_raise(Win32::Registry::Error, 1)
102
+ expect(described_class.compatible_version?).to be(false)
103
+ end
104
+ end
105
+
106
+ context 'when the Windows PowerShell major version is three' do
107
+ it 'returns true' do
108
+ expect(described_class).to receive(:version).and_return('3.0')
109
+ expect(described_class.compatible_version?).to be(true)
110
+ end
111
+ end
112
+
113
+ context 'when the Windows PowerShell major version is greater than three' do
114
+ it 'returns true' do
115
+ expect(described_class).to receive(:version).and_return('4.0')
116
+ expect(described_class.compatible_version?).to be(true)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end