Coverage for tests/unit_tests/utils/test_util.py: 100%

116 statements  

« prev     ^ index     » next       coverage.py v7.17.2, created at 2026-11-07 05:08 +0000

1# This file is part of the Apio project 

2# (C) 2016-present FPGAwars 

3# Project authors: 

4# * Jesús Arroyo (Jesus89) (2016-2019) 

5# * Juan Gonzalez (obijuan) (2019-2024) 

6# * The Apio Team (2024-present) 

7# License: GPLv2 

8 

9""" 

10Tests of util.py 

11""" 

12 

13import os 

14from pathlib import Path 

15import pytest 

16from tests.conftest import ApioRunner 

17from apio.common.debug_util import is_debug 

18from apio.utils.util import ( 

19 get_apio_release_info, 

20 plurality, 

21 list_plurality, 

22 pushd, 

23 # subprocess_call, 

24 compute_file_sha256, 

25 resolve_packages_dir, 

26) 

27 

28# TODO: Add more tests. 

29 

30 

31def test_release_info(): 

32 """Tests that the release info placeholder is empty. This value 

33 is set on the fly by build and publishing github workflows.""" 

34 version_info = get_apio_release_info() 

35 assert isinstance(version_info, str) 

36 assert version_info == "" 

37 

38 

39def test_pluraliry(): 

40 """Tests the plurality() function.""" 

41 # -- Test for ints 1, 2, 3 

42 assert plurality(1, "file") == "1 file" 

43 assert plurality(2, "file") == "2 files" 

44 assert plurality(3, "file") == "3 files" 

45 

46 # -- Test for lengths 1, 2, 3. 

47 assert plurality(["aa"], "file") == "1 file" 

48 assert plurality(["aa", "bb"], "file") == "2 files" 

49 assert plurality(["aa", "bb", "cc"], "file") == "3 files" 

50 

51 

52def test_list_pluraliry(): 

53 """Tests the list_plurality() function.""" 

54 

55 # -- Test for lengths 1, 2, and 3. 

56 assert list_plurality(["aa"], "or") == "aa" 

57 assert list_plurality(["aa", "bb"], "and") == "aa and bb" 

58 assert list_plurality(["aa", "bb", "cc"], "or") == "aa, bb, or cc" 

59 

60 # -- An empty list should trhow an assert exception. 

61 with pytest.raises(AssertionError): 

62 list_plurality([], "or") 

63 

64 

65def test_is_debug(): 

66 """Tests the is_debug() function.""" 

67 

68 # -- Assuming APIO_DEBUG is not defined. 

69 assert not is_debug(1) 

70 assert not is_debug(2) 

71 assert not is_debug(3) 

72 

73 # -- Enter debug mode level 1. 

74 os.environ["APIO_DEBUG"] = "1" 

75 assert is_debug(1) 

76 assert not is_debug(2) 

77 assert not is_debug(3) 

78 

79 # -- Enter debug mode level 2. 

80 os.environ["APIO_DEBUG"] = "2" 

81 assert is_debug(1) 

82 assert is_debug(2) 

83 assert not is_debug(3) 

84 

85 # -- Enter debug mode level 3. 

86 os.environ["APIO_DEBUG"] = "3" 

87 assert is_debug(1) 

88 assert is_debug(2) 

89 assert is_debug(3) 

90 

91 # -- Exit debug mode 

92 os.environ.pop("APIO_DEBUG") 

93 assert not is_debug(1) 

94 assert not is_debug(2) 

95 assert not is_debug(3) 

96 

97 

98def test_pushd(apio_runner: ApioRunner): 

99 """Test the pushd context manager.""" 

100 

101 with apio_runner.in_sandbox() as sb: 

102 # -- Define dir 1. 

103 dir1 = sb.proj_dir 

104 assert dir1.is_dir() 

105 

106 # -- Define dir 2 

107 dir2 = dir1 / "dir2" 

108 assert dir2.resolve() != dir1.resolve() 

109 dir2.mkdir() 

110 

111 # -- Change to dir1 

112 os.chdir(dir1) 

113 assert Path.cwd().resolve() == dir1.resolve() 

114 

115 # -- Pushd to dir 2 

116 with pushd(dir2): 

117 assert Path.cwd().resolve() == dir2.resolve() 

118 

119 # -- Back from pushd to dir1 

120 assert Path.cwd().resolve() == dir1.resolve() 

121 

122 

123def test_compute_file_sha256(apio_runner: ApioRunner): 

124 """Test compute_file_sha256().""" 

125 

126 with apio_runner.in_sandbox() as sb: 

127 

128 path = Path("./my-test-file") 

129 

130 # -- Test with an empty file. 

131 path = Path("./my-test-file1") 

132 sb.write_file(path, "") 

133 sha256 = compute_file_sha256(path) 

134 assert ( 

135 sha256 == "e3b0c44298fc1c149afbf4c8996fb92427" 

136 "ae41e4649b934ca495991b7852b855" 

137 ) 

138 

139 # -- Test with non empty file. 

140 path = Path("./my-test-file2") 

141 sb.write_file(path, "hello world") 

142 sha256 = compute_file_sha256(path) 

143 assert ( 

144 sha256 == "b94d27b9934d3e08a52e52d7da7dabfac" 

145 "484efe37a5380ee9088f7ace2efcde9" 

146 ) 

147 

148 

149def test_resolve_packages_dir_expanded_check(apio_runner: ApioRunner): 

150 """Tests that the 'packages' safety check of APIO_PACKAGES is applied 

151 to the value after the env vars expansion.""" 

152 

153 with apio_runner.in_sandbox() as sb: 

154 

155 # -- The original var value contains 'packages' but the expanded value 

156 # -- doesn't. Should fail. 

157 os.environ["packages_dir"] = str(sb.home_dir / "my-tools") 

158 os.environ["APIO_PACKAGES"] = "${packages_dir}" 

159 with apio_runner.with_logger() as log: 

160 with pytest.raises(SystemExit) as e: 

161 resolve_packages_dir(sb.home_dir) 

162 assert e.value.code == 1 

163 assert "should include the strings 'apio' and 'packages'" in log.out 

164 

165 # -- The original var value doesn't contain 'packages' but the expanded value 

166 # -- does. Should pass. 

167 os.environ["my_dir"] = str(sb.home_dir / "my-packages") 

168 os.environ["APIO_PACKAGES"] = "${my_dir}" 

169 assert resolve_packages_dir(sb.home_dir) == ( 

170 sb.home_dir / "my-packages" 

171 ) 

172 

173 

174def test_resolve_packages_dir_apio_and_packages_check( 

175 apio_runner: ApioRunner, 

176): 

177 """Tests that APIO_PACKAGES must contain both 'apio' and 'packages', 

178 case insensitive.""" 

179 

180 with apio_runner.in_sandbox() as sb: 

181 

182 # -- Case 1: Contains 'packages' but not 'apio'. Should fail. The check 

183 # -- happens before the dir is accessed so a fake path is ok. 

184 os.environ["APIO_PACKAGES"] = str(Path("/no-such-dir/my-packages")) 

185 with apio_runner.with_logger() as log: 

186 with pytest.raises(SystemExit) as e: 

187 resolve_packages_dir(sb.home_dir) 

188 assert e.value.code == 1 

189 assert "should include the strings 'apio' and 'packages'" in log.out 

190 

191 # -- Case 2: Contains 'apio' but not 'packages'. Should fail. 

192 os.environ["APIO_PACKAGES"] = str(Path("/no-such-dir/my-apio-tools")) 

193 with apio_runner.with_logger() as log: 

194 with pytest.raises(SystemExit) as e: 

195 resolve_packages_dir(sb.home_dir) 

196 assert e.value.code == 1 

197 assert "should include the strings 'apio' and 'packages'" in log.out 

198 

199 # -- Case 3: Contains neither 'apio' nor 'packages'. Should fail. 

200 os.environ["APIO_PACKAGES"] = str(Path("/no-such-dir/my-tools")) 

201 with apio_runner.with_logger() as log: 

202 with pytest.raises(SystemExit) as e: 

203 resolve_packages_dir(sb.home_dir) 

204 assert e.value.code == 1 

205 assert "should include the strings 'apio' and 'packages'" in log.out 

206 

207 # -- Case 4: Upper case 'PACKAGES' and 'APIO'. Should pass. 

208 os.environ["APIO_PACKAGES"] = str(sb.home_dir / "APIO-PACKAGES") 

209 assert resolve_packages_dir(sb.home_dir) == ( 

210 sb.home_dir / "APIO-PACKAGES" 

211 ) 

212 

213 

214def test_resolve_packages_dir_dot_dot(apio_runner: ApioRunner): 

215 """Tests that '..' path components in APIO_PACKAGES are rejected.""" 

216 

217 with apio_runner.in_sandbox() as sb: 

218 

219 # -- Case 1: '..' that removes the 'apio' and 'packages' component. 

220 # -- Should fail. 

221 os.environ["APIO_PACKAGES"] = str( 

222 Path("/no-such-dir/apio-packages/..") 

223 ) 

224 with apio_runner.with_logger() as log: 

225 with pytest.raises(SystemExit) as e: 

226 resolve_packages_dir(sb.home_dir) 

227 assert e.value.code == 1 

228 assert "should not contain '..'" in log.out 

229 

230 # -- Case 2: '..' that keeps the 'apio' and 'packages' component. 

231 # -- Should fail. 

232 os.environ["APIO_PACKAGES"] = str( 

233 Path("/no-such-dir/tmp/../apio-packages") 

234 ) 

235 with apio_runner.with_logger() as log: 

236 with pytest.raises(SystemExit) as e: 

237 resolve_packages_dir(sb.home_dir) 

238 assert e.value.code == 1 

239 assert "should not contain '..'" in log.out 

240 

241 # -- Case 3: '..' inside a dir name is not a '..' component. 

242 # -- Should pass. 

243 os.environ["APIO_PACKAGES"] = str(sb.sandbox_dir / "apio..packages") 

244 assert resolve_packages_dir(sb.home_dir) == ( 

245 sb.sandbox_dir / "apio..packages" 

246 )