Skip to content

Commit 7dd51aa

Browse files
committed
is_exe, is_readable: simpler, more robust
is_writable more robuse
1 parent 291f526 commit 7dd51aa

File tree

6 files changed

+72
-44
lines changed

6 files changed

+72
-44
lines changed

+stdlib/is_exe.m

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
arguments
77
p string
88
end
9-
% need to have string array type for p(:)
10-
11-
p = p(:);
129

1310
ok(size(p)) = false;
1411

@@ -29,9 +26,9 @@
2926
props = "Readable";
3027
end
3128

32-
t(i, :) = getPermissions(filePermissions(p(i)), props);
29+
t = getPermissions(filePermissions(p(i)), props);
3330

34-
ok(i) = any(t{i,:}, 2);
31+
ok(i) = any(t{:,:}, 2);
3532

3633
else
3734

@@ -41,6 +38,3 @@
4138
end
4239

4340
end
44-
45-
%!assert (!is_exe("."))
46-
%!assert (is_exe(program_invocation_name))

+stdlib/is_readable.m

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
%% IS_READABLE is file readable
2+
%
3+
%%% Inputs
4+
% p: string array of file paths
5+
%% Outputs
6+
% ok: logical array of the same size as p, true if file is readable
27

38
function ok = is_readable(p)
9+
arguments
10+
p string
11+
end
12+
13+
ok(size(p)) = false;
14+
15+
i = stdlib.exists(p);
16+
17+
if ~any(i), return, end
18+
19+
if ~isMATLABReleaseOlderThan('R2025a')
420

5-
try
621
props = "Readable";
722
if isunix
823
props = [props, "GroupRead", "OtherRead"];
924
end
10-
t = getPermissions(filePermissions(p), props);
11-
ok = any(t{:,:}, 2);
12-
catch e
13-
switch e.identifier
14-
case {'MATLAB:UndefinedFunction', 'Octave:undefined-function'}
15-
a = file_attributes_legacy(p);
16-
ok = a.UserRead || a.GroupRead || a.OtherRead;
17-
otherwise, rethrow(e)
18-
end
25+
26+
t = getPermissions(filePermissions(p(i)), props);
27+
ok(i) = any(t{:,:}, 2);
28+
29+
else
30+
31+
a = file_attributes_legacy(p);
32+
ok = a.UserRead || a.GroupRead || a.OtherRead;
33+
1934
end
2035

2136
end
22-
%!assert (is_readable('is_readable.m'))

+stdlib/is_writable.m

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
%% IS_WRITABLE is path writable
2+
%
3+
%%% Inputs
4+
% p: string array of file paths
5+
%% Outputs
6+
% ok: logical array of the same size as p, true if file is writable
27

38
function ok = is_writable(p)
9+
arguments
10+
p string
11+
end
12+
13+
ok(size(p)) = false;
14+
15+
i = stdlib.exists(p);
16+
17+
if ~any(i), return, end
18+
19+
if ~isMATLABReleaseOlderThan('R2025a')
420

5-
try
621
props = "Writable";
722
if isunix
823
props = [props, "GroupWrite", "OtherWrite"];
924
end
10-
t = getPermissions(filePermissions(p), props);
11-
ok = any(t{:,:}, 2);
12-
catch e
13-
switch e.identifier
14-
case {'MATLAB:UndefinedFunction', 'Octave:undefined-function'}
15-
a = file_attributes_legacy(p);
16-
ok = a.UserWrite || a.GroupWrite || a.OtherWrite;
17-
otherwise, rethrow(e)
18-
end
25+
26+
t = getPermissions(filePermissions(p(i)), props);
27+
ok(i) = any(t{:,:}, 2);
28+
29+
else
30+
a = file_attributes_legacy(p);
31+
ok = a.UserWrite || a.GroupWrite || a.OtherWrite;
1932
end
2033

2134
end

test/TestExists.m

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,42 @@
11
classdef TestExists < matlab.unittest.TestCase
22

33
properties(TestParameter)
4-
Ps = {{pwd(), true}, {mfilename("fullpath") + ".m", true}, ...
5-
{"TestFileImpure.m", true}}
4+
Ps = {
5+
{pwd(), true}, ...
6+
{mfilename("fullpath") + ".m", true}, ...
7+
{fileparts(mfilename("fullpath")) + "/../Readme.md", true}, ...
8+
{tempname(), false}
9+
}
610
% on CI matlabroot can be writable!
711
end
812

913
methods (Test, TestTags="impure")
1014

1115
function test_exists(tc, Ps)
1216
ok = stdlib.exists(Ps{1});
13-
tc.verifyEqual(ok, Ps{2})
17+
tc.verifyEqual(ok, Ps{2}, Ps{1})
1418
end
1519

1620

1721
function test_is_readable(tc, Ps)
1822
ok = stdlib.is_readable(Ps{1});
19-
tc.verifyEqual(ok, Ps{2})
23+
tc.verifyEqual(ok, Ps{2}, Ps{1})
2024
end
2125

2226

27+
function test_is_writable(tc, Ps)
28+
ok = stdlib.is_writable(Ps{1});
29+
tc.verifyEqual(ok, Ps{2}, Ps{1})
30+
end
31+
32+
function test_is_writable_dir(tc)
33+
tc.assumeFalse(isMATLABReleaseOlderThan('R2022a'))
34+
35+
td = tc.createTemporaryFolder();
36+
37+
tc.verifyTrue(stdlib.is_writable(td))
38+
end
39+
2340
end
2441

2542
end

test/TestFileImpure.m

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
classdef TestFileImpure < matlab.unittest.TestCase
22

33
properties(TestParameter)
4-
p_is_writable = {{pwd(), true}};
5-
64
p_same = {...
75
{"..", "./.."}, ...
86
{"..", pwd() + "/.."}, ...
@@ -22,12 +20,6 @@ function test_file_size(tc, p_file_size)
2220
end
2321

2422

25-
function test_is_writable(tc, p_is_writable)
26-
ok = stdlib.is_writable(p_is_writable{1});
27-
tc.verifyEqual(ok, p_is_writable{2})
28-
end
29-
30-
3123
function test_null_file(tc)
3224
import matlab.unittest.constraints.IsFile
3325
tc.assumeFalse(ispc)

test/TestIsExe.m

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
classdef TestIsExe < matlab.unittest.TestCase
22

33
properties (TestParameter)
4-
p = {{fileparts(mfilename('fullpath')) + "/../Readme.md", false}}
4+
p = {{fileparts(mfilename('fullpath')) + "/../Readme.md", false}, {"not-exist", false}}
55
end
66

77
methods(Test, TestTags="impure")
88

99
function test_is_exe(tc, p)
10-
tc.assumeThat(p{1}, matlab.unittest.constraints.IsFile)
11-
1210
tc.verifyEqual(stdlib.is_exe(p{1}), p{2})
1311
end
1412

0 commit comments

Comments
 (0)