file_permissions 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # The currently loaded version.
24
+ #
25
+ # Using Semantic Versioning (2.0.0) rules
26
+ # @see http://semver.org/spec/v2.0.0.html
27
+ VERSION = '0.1.0'.freeze
28
+
29
+ end
30
+ end
@@ -0,0 +1,345 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ describe ComplexMode do
24
+ describe ".build" do
25
+ it "should return the same object if a ComplexMode is given" do
26
+ existing_mode = ComplexMode.new(5)
27
+
28
+ mode = ComplexMode.build(existing_mode)
29
+
30
+ expect(mode).to equal existing_mode
31
+ end
32
+
33
+ it "should create a new instance if given something else" do
34
+ argument = [:user_read, :user_write, :group_read, :other_execute, :sticky]
35
+
36
+ expect(ComplexMode).to receive(:new).once.with(argument)
37
+
38
+ ComplexMode.build(argument)
39
+ end
40
+ end
41
+
42
+ describe ".new" do
43
+ it "should handle an octal representation" do
44
+ complex_mode = ComplexMode.new(00610)
45
+ expect(complex_mode.user).to eql Mode.parse('rw')
46
+ expect(complex_mode.group).to eql Mode.parse('x')
47
+ end
48
+
49
+ it "should handle a list of mode components" do
50
+ complex_mode = ComplexMode.new(
51
+ :user_read, :user_write, :user_execute, :group_read, :group_execute, :other_execute, :setgid, :sticky)
52
+
53
+ expect(complex_mode.user).to eql Mode.parse('rwx')
54
+ expect(complex_mode.group).to eql Mode.parse('rx')
55
+ expect(complex_mode.other).to eql Mode.parse('x')
56
+ expect(complex_mode.special).to eql SpecialMode.parse('-st')
57
+ end
58
+
59
+ it "should handle a Set of mode components" do
60
+ mode = ComplexMode.new(Set[:user_read, :group_read, :group_execute, :setuid, :sticky])
61
+
62
+ expect(mode.user.read?).to eql true
63
+ expect(mode.user.write?).to eql false
64
+ expect(mode.user.execute?).to eql false
65
+
66
+ expect(mode.group.read?).to eql true
67
+ expect(mode.group.write?).to eql false
68
+ expect(mode.group.execute?).to eql true
69
+
70
+ expect(mode.other.read?).to eql false
71
+ expect(mode.other.write?).to eql false
72
+ expect(mode.other.execute?).to eql false
73
+
74
+ expect(mode.special.setuid?).to eql true
75
+ expect(mode.special.setgid?).to eql false
76
+ expect(mode.special.sticky?).to eql true
77
+ end
78
+
79
+ it "should complain about invalid input" do
80
+ expect {
81
+ ComplexMode.new(:wrong, :user_execute)
82
+ }.to raise_error(ArgumentError)
83
+ end
84
+ end
85
+
86
+ describe ".from_file" do
87
+ before(:each) do
88
+ @test_directory = Pathname.new(Dir.mktmpdir('file_permissions_spec'))
89
+ end
90
+
91
+ after(:each) do
92
+ @test_directory.rmtree
93
+ end
94
+
95
+ it "should create a complex mode from file" do
96
+ test_file = (@test_directory + 'test_file')
97
+ FileUtils.touch(test_file)
98
+ test_file.chmod(05641)
99
+
100
+ complex_mode = ComplexMode.from_file(test_file)
101
+ expect(complex_mode.to_i).to eql 05641
102
+ end
103
+
104
+ it "should create a complex mode from file given as string" do
105
+ test_file = (@test_directory + 'test_file')
106
+ FileUtils.touch(test_file)
107
+ test_file.chmod(05641)
108
+
109
+ complex_mode = ComplexMode.from_file(test_file.to_s)
110
+ expect(complex_mode.to_i).to eql 05641
111
+ end
112
+
113
+ it "should create a complex mode from the resolved symlink" do
114
+ test_file = (@test_directory + 'test_file')
115
+ FileUtils.touch(test_file)
116
+ test_file.chmod(05641)
117
+
118
+ test_link = (@test_directory + 'test_link')
119
+ test_link.make_symlink(test_file)
120
+
121
+ complex_mode = ComplexMode.from_file(test_link)
122
+ expect(complex_mode.to_i).to eql 05641
123
+ end
124
+
125
+ it "should create a complex mode from the symlink itself if in 'target symlinks' mode" do
126
+ test_file = (@test_directory + 'test_file')
127
+ FileUtils.touch(test_file)
128
+ test_file.chmod(05641)
129
+
130
+ test_link = (@test_directory + 'test_link')
131
+ test_link.make_symlink(test_file)
132
+
133
+ complex_mode = ComplexMode.from_file(test_link, :target_symlinks)
134
+ expect(complex_mode.to_i).to eql 00777
135
+ end
136
+
137
+ it "should complain about an invalid symlink handling" do
138
+ test_file = (@test_directory + 'test_file')
139
+ FileUtils.touch(test_file)
140
+
141
+ expect {
142
+ ComplexMode.from_file(test_file, :invalid)
143
+ }.to raise_error(ArgumentError, "Invalid symlink handling: :invalid")
144
+ end
145
+ end
146
+
147
+ describe "#user" do
148
+ it "should return return the user's attributes as mode if setuid is set" do
149
+ complex_mode = ComplexMode.new(07710)
150
+ expect(complex_mode.user).to eql Mode.parse('rwx')
151
+ end
152
+
153
+ it "should return return the user's attributes as mode if setuid is unset" do
154
+ complex_mode = ComplexMode.new(00510)
155
+ expect(complex_mode.user).to eql Mode.parse('rx')
156
+ end
157
+ end
158
+
159
+ describe "#group" do
160
+ it "should return return the group's attributes as mode if setgid is set" do
161
+ complex_mode = ComplexMode.new(07770)
162
+ expect(complex_mode.group).to eql Mode.parse('rwx')
163
+ end
164
+
165
+ it "should return return the group's attributes as mode if setgid is unset" do
166
+ complex_mode = ComplexMode.new(00530)
167
+ expect(complex_mode.group).to eql Mode.parse('wx')
168
+ end
169
+ end
170
+
171
+ describe "#assign_to_file" do
172
+ before(:each) do
173
+ @test_directory = Pathname.new(Dir.mktmpdir('file_permissions_spec'))
174
+ end
175
+
176
+ after(:each) do
177
+ @test_directory.rmtree
178
+ end
179
+
180
+ it "should assign a complex mode to file" do
181
+ test_file = (@test_directory + 'test_file')
182
+ FileUtils.touch(test_file)
183
+
184
+ complex_mode = ComplexMode.new(05641)
185
+ complex_mode.assign_to_file(test_file)
186
+
187
+ expect(test_file.stat.mode & 0b111_111_111_111).to eql 05641
188
+ end
189
+
190
+ it "should assign a complex mode to file" do
191
+ test_file = (@test_directory + 'test_file')
192
+ FileUtils.touch(test_file)
193
+
194
+ complex_mode = ComplexMode.new(05641)
195
+ complex_mode.assign_to_file(test_file.to_s)
196
+
197
+ expect(test_file.stat.mode & 0b111_111_111_111).to eql 05641
198
+ end
199
+
200
+ it "should assign a complex mode to the resolved symlink" do
201
+ test_file = (@test_directory + 'test_file')
202
+ FileUtils.touch(test_file)
203
+
204
+ test_link = (@test_directory + 'test_link')
205
+ test_link.make_symlink(test_file)
206
+
207
+ complex_mode = ComplexMode.new(05641)
208
+ complex_mode.assign_to_file(test_link)
209
+
210
+ expect(test_file.stat.mode & 0b111_111_111_111).to eql 05641
211
+ end
212
+
213
+ it "should complain about missing lchmod function in 'target symlinks' mode" do
214
+ test_file = (@test_directory + 'test_file')
215
+ FileUtils.touch(test_file)
216
+
217
+ test_link = (@test_directory + 'test_link')
218
+ test_link.make_symlink(test_file)
219
+
220
+ complex_mode = ComplexMode.new(05641)
221
+
222
+ expect {
223
+ complex_mode.assign_to_file(test_link, :target_symlinks)
224
+ }.to raise_error(NotImplementedError, "lchmod function is not available in current OS or Ruby environment")
225
+ end
226
+
227
+ it "should assign a complex mode to the symlink itself in 'target symlinks' mode" do
228
+ pending "This test is intended for systems where there is a lchmod function. No idea which system that may be. Have fun."
229
+
230
+ test_file = (@test_directory + 'test_file')
231
+ FileUtils.touch(test_file)
232
+
233
+ test_link = (@test_directory + 'test_link')
234
+ test_link.make_symlink(test_file)
235
+
236
+ complex_mode = ComplexMode.new(05641)
237
+ complex_mode.assign_to_file(test_link, :target_symlinks)
238
+
239
+ expect(test_file.stat.mode & 0b111_111_111_111).to eql 05641
240
+ end
241
+
242
+ it "should complain about an invalid symlink handling" do
243
+ test_file = (@test_directory + 'test_file')
244
+ FileUtils.touch(test_file)
245
+
246
+ complex_mode = ComplexMode.new(05641)
247
+
248
+ expect {
249
+ complex_mode.assign_to_file(test_file, :invalid)
250
+ }.to raise_error(ArgumentError, "Invalid symlink handling: :invalid")
251
+ end
252
+ end
253
+
254
+ describe "#inspect" do
255
+ it "should represent the user, group and other read and write flags" do
256
+ complex_mode = ComplexMode.new(00765)
257
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "rwxrw-r-x">'
258
+ end
259
+
260
+ it "should represent the setuid flag if user execute flag is set" do
261
+ complex_mode = ComplexMode.new(04715)
262
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "rws--xr-x">'
263
+ end
264
+
265
+ it "should represent the setuid flag if user execute flag is unset" do
266
+ complex_mode = ComplexMode.new(04615)
267
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "rwS--xr-x">'
268
+ end
269
+
270
+ it "should represent the setgid flag if group execute flag is set" do
271
+ complex_mode = ComplexMode.new(02615)
272
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "rw---sr-x">'
273
+ end
274
+
275
+ it "should represent the setgid flag if group execute flag is unset" do
276
+ complex_mode = ComplexMode.new(02605)
277
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "rw---Sr-x">'
278
+ end
279
+
280
+ it "should represent the sticky flag if other execute flag is set" do
281
+ complex_mode = ComplexMode.new(01435)
282
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "r---wxr-t">'
283
+ end
284
+
285
+ it "should represent the sticky flag if other execute flag is unset" do
286
+ complex_mode = ComplexMode.new(07004)
287
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "--S--Sr-T">'
288
+ end
289
+ end
290
+
291
+ describe "#inspect" do
292
+ it "should give a decent string representation for debugging" do
293
+ complex_mode = ComplexMode.new(07004)
294
+ expect(complex_mode.inspect).to eql '#<GodObject::FilePermissions::ComplexMode: "--S--Sr-T">'
295
+ end
296
+ end
297
+
298
+ describe "#to_s" do
299
+ it "should represent the user, group and other read and write flags" do
300
+ complex_mode = ComplexMode.new(00765)
301
+ expect(complex_mode.to_s).to eql 'rwxrw-r-x'
302
+ end
303
+
304
+ it "should represent the setuid flag if user execute flag is set" do
305
+ complex_mode = ComplexMode.new(04715)
306
+ expect(complex_mode.to_s).to eql 'rws--xr-x'
307
+ end
308
+
309
+ it "should represent the setuid flag if user execute flag is unset" do
310
+ complex_mode = ComplexMode.new(04615)
311
+ expect(complex_mode.to_s).to eql 'rwS--xr-x'
312
+ end
313
+
314
+ it "should represent the setgid flag if group execute flag is set" do
315
+ complex_mode = ComplexMode.new(02615)
316
+ expect(complex_mode.to_s).to eql 'rw---sr-x'
317
+ end
318
+
319
+ it "should represent the setgid flag if group execute flag is unset" do
320
+ complex_mode = ComplexMode.new(02605)
321
+ expect(complex_mode.to_s).to eql 'rw---Sr-x'
322
+ end
323
+
324
+ it "should represent the sticky flag if other execute flag is set" do
325
+ complex_mode = ComplexMode.new(01435)
326
+ expect(complex_mode.to_s).to eql 'r---wxr-t'
327
+ end
328
+
329
+ it "should represent the sticky flag if other execute flag is unset" do
330
+ complex_mode = ComplexMode.new(07004)
331
+ expect(complex_mode.to_s).to eql '--S--Sr-T'
332
+ end
333
+ end
334
+
335
+ describe "#to_i" do
336
+ it "should return the correct octal representation" do
337
+ complex_mode = ComplexMode.new(02615)
338
+
339
+ expect(complex_mode.to_i).to eql 02615
340
+ end
341
+ end
342
+ end
343
+
344
+ end
345
+ end
@@ -0,0 +1,396 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ describe Mode do
24
+ describe ".build" do
25
+ it "should return the same object if a Mode is given" do
26
+ existing_mode = Mode.new(5)
27
+
28
+ mode = Mode.build(existing_mode)
29
+
30
+ expect(mode).to equal existing_mode
31
+ end
32
+
33
+ it "should create a new instance through parsing if given a String" do
34
+ argument = 's-t'
35
+
36
+ expect(Mode).to receive(:parse).once.with(argument)
37
+
38
+ Mode.build(argument)
39
+ end
40
+
41
+ it "should create a new instance if given something else" do
42
+ argument = 4
43
+
44
+ expect(Mode).to receive(:new).once.with(argument)
45
+
46
+ Mode.build(argument)
47
+ end
48
+ end
49
+
50
+ describe ".parse" do
51
+ context "given an octal representation" do
52
+ it "should return an empty set if a 0 is given" do
53
+ expect(Mode.parse('0')).to eql Mode.new(Set[])
54
+ end
55
+
56
+ it "should return a set including the execute token if a 1 is given" do
57
+ expect(Mode.parse('1')).to eql Mode.new(Set[:execute])
58
+ end
59
+
60
+ it "should return a set including the write token if a 2 is given" do
61
+ expect(Mode.parse('2')).to eql Mode.new(Set[:write])
62
+ end
63
+
64
+ it "should return a set including the write and execute tokens if a 3 is given" do
65
+ expect(Mode.parse('3')).to eql Mode.new(Set[:write, :execute])
66
+ end
67
+
68
+ it "should return a set including the read token if a 4 is given" do
69
+ expect(Mode.parse('4')).to eql Mode.new(Set[:read])
70
+ end
71
+
72
+ it "should return a set including the read and execute tokens if a 5 is given" do
73
+ expect(Mode.parse('5')).to eql Mode.new(Set[:read, :execute])
74
+ end
75
+
76
+ it "should return a set including the read and write tokens if a 6 is given" do
77
+ expect(Mode.parse('6')).to eql Mode.new(Set[:read, :write])
78
+ end
79
+
80
+ it "should return a set including the read, write and execute tokens if a 7 is given" do
81
+ expect(Mode.parse('7')).to eql Mode.new(Set[:read, :write, :execute])
82
+ end
83
+
84
+ it "should raise an exception if 8 is given" do
85
+ expect {
86
+ Mode.parse('8')
87
+ }.to raise_error(ParserError, 'Invalid format')
88
+ end
89
+ end
90
+
91
+ context "representation in symbolic mode" do
92
+ it "should complain about duplicate read symbols" do
93
+ expect {
94
+ Mode.parse('r-r')
95
+ }.to raise_error(ParserError, 'Duplicate digit in: "r-r"')
96
+ end
97
+
98
+ it "should complain about duplicate write symbols" do
99
+ expect {
100
+ Mode.parse('www')
101
+ }.to raise_error(ParserError, 'Duplicate digit in: "www"')
102
+ end
103
+
104
+ it "should complain about duplicate execute symbols" do
105
+ expect {
106
+ Mode.parse('xx-')
107
+ }.to raise_error(ParserError, 'Duplicate digit in: "xx-"')
108
+ end
109
+
110
+ it "should complain about invalid symbols" do
111
+ expect {
112
+ Mode.parse('r-a')
113
+ }.to raise_error(ParserError, 'Invalid format')
114
+ end
115
+
116
+ it "should not complain about duplicate null symbols" do
117
+ expect {
118
+ Mode.parse('-r-')
119
+ }.not_to raise_error
120
+ end
121
+
122
+ it "should parse the read symbol" do
123
+ result = Mode.parse('r')
124
+ expect(result).to eql Mode.new(Set[:read])
125
+ end
126
+
127
+ it "should parse the write symbol" do
128
+ result = Mode.parse('w')
129
+ expect(result).to eql Mode.new(Set[:write])
130
+ end
131
+
132
+ it "should parse the execute symbol" do
133
+ result = Mode.parse('x')
134
+ expect(result).to eql Mode.new(Set[:execute])
135
+ end
136
+ end
137
+ end
138
+
139
+ describe ".new" do
140
+ it "should handle no parameters" do
141
+ mode = Mode.new
142
+ expect(mode).to be_a(Mode)
143
+ expect(mode.read?).to eql false
144
+ expect(mode.write?).to eql false
145
+ expect(mode.execute?).to eql false
146
+ expect(mode.to_i).to eql 0
147
+ expect(mode.to_s).to eql "---"
148
+ expect(mode.to_s(:short)).to eql "-"
149
+ attributes = { read: false, write: false, execute: false }
150
+ expect(mode.state).to eql attributes
151
+ end
152
+
153
+ it "should handle a Set" do
154
+ mode = Mode.new(Set[:read, :execute])
155
+
156
+ expect(mode.state).to eql(read: true, write: false, execute: true)
157
+ expect(mode.read?).to eql true
158
+ expect(mode.write?).to eql false
159
+ expect(mode.execute?).to eql true
160
+ end
161
+
162
+ it "should handle an array of mode components" do
163
+ mode = Mode.new(:read, :write, :execute)
164
+ attributes = { read: true, write: true, execute: true }
165
+
166
+ expect(mode.state).to eql attributes
167
+ end
168
+ end
169
+
170
+ let(:empty_mode) { Mode.parse('---') }
171
+ let(:x_mode) { Mode.parse('--x') }
172
+ let(:w_mode) { Mode.parse('-w-') }
173
+ let(:wx_mode) { Mode.parse('-wx') }
174
+ let(:r_mode) { Mode.parse('r--') }
175
+ let(:rx_mode) { Mode.parse('r-x') }
176
+ let(:rw_mode) { Mode.parse('rw-') }
177
+ let(:rwx_mode) { Mode.parse('rwx') }
178
+
179
+ describe "#==" do
180
+ it "should be true if compare to itself" do
181
+ expect(empty_mode).to eq(empty_mode)
182
+ end
183
+
184
+ it "should be false if read attributes differ" do
185
+ expect(rx_mode).not_to eq(x_mode)
186
+ end
187
+
188
+ it "should be false if write attributes differ" do
189
+ expect(wx_mode).not_to eq(x_mode)
190
+ end
191
+
192
+ it "should be false if execute attributes differ" do
193
+ expect(wx_mode).not_to eq(w_mode)
194
+ end
195
+
196
+ it "should be true if compared to a Mode with same attributes" do
197
+ expect(empty_mode).to eq(Mode.new)
198
+ end
199
+
200
+ it "should be true if compared to an ACL-like with the same entries?" do
201
+ other = OpenStruct.new(
202
+ to_i: 6, configuration: OpenStruct.new(digits: [:read, :write, :execute])
203
+ )
204
+
205
+ expect(rw_mode).to eq(other)
206
+ end
207
+ end
208
+
209
+ describe "#eql?" do
210
+ it "should be true if compare to itself" do
211
+ expect(Mode.new).to eql Mode.new
212
+ end
213
+
214
+ it "should be false if attributes are the same but class differs" do
215
+ other = OpenStruct.new(attribute: { read: false, write: false, execute: false })
216
+ expect(Mode.new).not_to eql other
217
+ end
218
+ end
219
+
220
+ describe "#<=>" do
221
+ it "should return -1 if the compared Mode has a higher octal representation" do
222
+ expect(w_mode <=> r_mode).to eql -1
223
+ end
224
+
225
+ it "should return 1 if the compared Mode has a lower octal representation" do
226
+ expect(r_mode <=> w_mode).to eql 1
227
+ end
228
+
229
+ it "should return 0 if the compared Mode has an equal octal representation" do
230
+ expect(x_mode <=> x_mode).to eql 0
231
+ end
232
+
233
+ it "should return nil if the compared object is incompatible" do
234
+ expect(w_mode <=> :something).to eql nil
235
+ end
236
+ end
237
+
238
+ describe "#inspect" do
239
+ it "should give a decent string representation for debugging" do
240
+ expect(rwx_mode.inspect).to eq("#<#{subject.class}: \"rwx\">")
241
+ expect(rw_mode.inspect).to eq("#<#{subject.class}: \"rw-\">")
242
+ expect(rx_mode.inspect).to eq("#<#{subject.class}: \"r-x\">")
243
+ expect(wx_mode.inspect).to eq("#<#{subject.class}: \"-wx\">")
244
+ expect(r_mode.inspect).to eq("#<#{subject.class}: \"r--\">")
245
+ expect(w_mode.inspect).to eq("#<#{subject.class}: \"-w-\">")
246
+ expect(x_mode.inspect).to eq("#<#{subject.class}: \"--x\">")
247
+ expect(empty_mode.inspect).to eq("#<#{subject.class}: \"---\">")
248
+ end
249
+ end
250
+
251
+ describe "#to_s" do
252
+ it "should represent attributes as string in long mode" do
253
+ expect(rwx_mode.to_s(:long)).to eq("rwx")
254
+ expect(rw_mode.to_s(:long)).to eq("rw-")
255
+ expect(rx_mode.to_s(:long)).to eq("r-x")
256
+ expect(wx_mode.to_s(:long)).to eq("-wx")
257
+ expect(r_mode.to_s(:long)).to eq("r--")
258
+ expect(w_mode.to_s(:long)).to eq("-w-")
259
+ expect(x_mode.to_s(:long)).to eq("--x")
260
+ expect(empty_mode.to_s(:long)).to eq("---")
261
+ end
262
+
263
+ it "should represent attributes as string in short mode" do
264
+ expect(rwx_mode.to_s(:short)).to eq("rwx")
265
+ expect(rw_mode.to_s(:short)).to eq("rw")
266
+ expect(rx_mode.to_s(:short)).to eq("rx")
267
+ expect(wx_mode.to_s(:short)).to eq("wx")
268
+ expect(r_mode.to_s(:short)).to eq("r")
269
+ expect(w_mode.to_s(:short)).to eq("w")
270
+ expect(x_mode.to_s(:short)).to eq("x")
271
+ expect(empty_mode.to_s(:short)).to eq("-")
272
+ end
273
+ end
274
+
275
+ describe "#to_i" do
276
+ it "should represent no attributes in octal" do
277
+ expect(empty_mode.to_i).to eql 0
278
+ end
279
+
280
+ it "should represent execute attribute in octal" do
281
+ expect(x_mode.to_i).to eql 1
282
+ end
283
+
284
+ it "should represent write attribute in octal" do
285
+ expect(w_mode.to_i).to eql 2
286
+ end
287
+
288
+ it "should represent execute and write attributes in octal" do
289
+ expect(wx_mode.to_i).to eql 3
290
+ end
291
+
292
+ it "should represent read attribute in octal" do
293
+ expect(r_mode.to_i).to eql 4
294
+ end
295
+
296
+ it "should represent read and execute attributes in octal" do
297
+ expect(rx_mode.to_i).to eql 5
298
+ end
299
+
300
+ it "should represent read and write attributes in octal" do
301
+ expect(rw_mode.to_i).to eql 6
302
+ end
303
+
304
+ it "should represent read, write and execute attributes in octal" do
305
+ expect(rwx_mode.to_i).to eql 7
306
+ end
307
+ end
308
+
309
+ describe "#read?" do
310
+ it "should be true if read attribute is set" do
311
+ expect(r_mode.read?).to eql true
312
+ end
313
+
314
+ it "should be false if read attribute is not set" do
315
+ expect(wx_mode.read?).to eql false
316
+ end
317
+ end
318
+
319
+ describe "#write?" do
320
+ it "should be true if write attribute is set" do
321
+ expect(wx_mode.write?).to eql true
322
+ end
323
+
324
+ it "should be false if write attribute is not set" do
325
+ expect(rx_mode.write?).to eql false
326
+ end
327
+ end
328
+
329
+ describe "#execute?" do
330
+ it "should be true if execute attribute is set" do
331
+ expect(rx_mode.execute?).to eql true
332
+ end
333
+
334
+ it "should be false if execute attribute is not set" do
335
+ expect(empty_mode.execute?).to eql false
336
+ end
337
+ end
338
+
339
+ describe "#invert" do
340
+ it "should create a new Mode with all digits inverted" do
341
+ result = rx_mode.invert
342
+
343
+ expect(result).not_to equal rx_mode
344
+ expect(result).to eql w_mode
345
+ end
346
+ end
347
+
348
+ describe "#-" do
349
+ it "should create a new Mode from the first operand without the digits of the second operand" do
350
+ result = rwx_mode - w_mode
351
+
352
+ expect(result).not_to equal rwx_mode
353
+ expect(result).not_to equal w_mode
354
+ expect(result).to eql rx_mode
355
+ end
356
+ end
357
+
358
+ [:intersection, :&].each do |method_name|
359
+ describe "##{method_name}" do
360
+ it "should create a new Mode with only those digits enabled that are enabled in both operands" do
361
+ result = rw_mode.public_send(method_name, wx_mode)
362
+
363
+ expect(result).not_to equal rw_mode
364
+ expect(result).not_to equal wx_mode
365
+ expect(result).to eql w_mode
366
+ end
367
+ end
368
+ end
369
+
370
+ [:union, :|, :+].each do |method_name|
371
+ describe "##{method_name}" do
372
+ it "should create a new Mode with all enabled digits of both operands" do
373
+ result = r_mode.public_send(method_name, w_mode)
374
+
375
+ expect(result).not_to equal r_mode
376
+ expect(result).not_to equal w_mode
377
+ expect(result).to eql rw_mode
378
+ end
379
+ end
380
+ end
381
+
382
+ [:symmetric_difference, :^].each do |method_name|
383
+ describe "##{method_name}" do
384
+ it "should create a new Mode with only those digits enabled that are enabled in only one operand" do
385
+ result = rwx_mode.public_send(method_name, x_mode)
386
+
387
+ expect(result).not_to equal rwx_mode
388
+ expect(result).not_to equal x_mode
389
+ expect(result).to eql rw_mode
390
+ end
391
+ end
392
+ end
393
+ end
394
+
395
+ end
396
+ end