1#!/usr/local/bin/python3.8 2 3# Copyright 2014-2015 Steven Watanabe 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 6 7# Tests the link-directory rule used to create the 8# common boost/ directory in the new git layout. 9 10import BoostBuild 11 12def ignore_config(t): 13 """These files are created by the configuration logic in link.jam 14 They may or may not exist, depending on the system.""" 15 t.ignore("bin/symlink/test-hardlink") 16 t.ignore("bin/test-hardlink-source") 17 t.ignore("bin/test-symlink") 18 t.ignore("bin/test-symlink-source") 19 20def test_basic(): 21 """Test creation of a single link""" 22 t = BoostBuild.Tester() 23 t.write("jamroot.jam", """\ 24 import link ; 25 link-directory dir1-link : src/dir1/include : <location>. ; 26 """) 27 28 t.write("src/dir1/include/file1.h", "file1") 29 30 t.run_build_system() 31 32 t.expect_addition("include/file1.h") 33 t.expect_content("include/file1.h", "file1") 34 ignore_config(t) 35 t.expect_nothing_more() 36 t.cleanup() 37 38def test_merge_two(): 39 """Test merging two directories""" 40 t = BoostBuild.Tester() 41 t.write("jamroot.jam", """\ 42 import link ; 43 link-directory dir1-link : src/dir1/include : <location>. ; 44 link-directory dir2-link : src/dir2/include : <location>. ; 45 """) 46 47 t.write("src/dir1/include/file1.h", "file1") 48 t.write("src/dir2/include/file2.h", "file2") 49 50 t.run_build_system() 51 52 t.expect_addition("include/file1.h") 53 t.expect_content("include/file1.h", "file1") 54 t.expect_addition("include/file2.h") 55 t.expect_content("include/file2.h", "file2") 56 ignore_config(t) 57 t.expect_nothing_more() 58 t.cleanup() 59 60def test_merge_existing(group1, group2): 61 """Test adding a link when a different symlink already exists""" 62 t = BoostBuild.Tester() 63 t.write("jamroot.jam", """\ 64 import link ; 65 link-directory dir1-link : src/dir1/include : <location>. ; 66 link-directory dir2-link : src/dir2/include : <location>. ; 67 """) 68 69 t.write("src/dir1/include/file1.h", "file1") 70 t.write("src/dir2/include/file2.h", "file2") 71 72 t.run_build_system(group1) 73 74 if "dir1-link" in group1: 75 t.expect_addition("include/file1.h") 76 t.expect_content("include/file1.h", "file1") 77 if "dir2-link" in group1: 78 t.expect_addition("include/file2.h") 79 t.expect_content("include/file2.h", "file2") 80 ignore_config(t) 81 t.expect_nothing_more() 82 83 t.run_build_system(group2) 84 85 if "dir1-link" in group2: 86 if "dir1-link" not in group1: 87 t.expect_addition("include/file1.h") 88 else: 89 # When a directory is split the link needs to be recreated. 90 # On Windows, the test system checks the mod time of the 91 # link rather than the link target, so this may be seen as 92 # an update. 93 t.ignore_touch("include/file1.h") 94 t.expect_content("include/file1.h", "file1") 95 else: 96 t.ignore_removal("include/file1.h") 97 98 if "dir2-link" in group2: 99 if "dir2-link" not in group1: 100 t.expect_addition("include/file2.h") 101 else: 102 t.ignore_touch("include/file2.h") 103 t.expect_content("include/file2.h", "file2") 104 else: 105 t.ignore_removal("include/file2.h") 106 ignore_config(t) 107 t.expect_nothing_more() 108 109 t.cleanup() 110 111def test_merge_existing_all(): 112 test_merge_existing(["dir1-link"], ["dir2-link"]) 113 test_merge_existing(["dir2-link"], ["dir1-link"]) 114 test_merge_existing(["dir1-link"], ["dir1-link", "dir2-link"]) 115 test_merge_existing(["dir2-link"], ["dir1-link", "dir2-link"]) 116 117def test_merge_recursive(): 118 "Test merging several directories including common prefixes" 119 t = BoostBuild.Tester() 120 t.write("jamroot.jam", """\ 121 import link ; 122 link-directory dir1-link : src/dir1/include : <location>. ; 123 link-directory dir2-link : src/dir2/include : <location>. ; 124 link-directory dir3-link : src/dir3/include : <location>. ; 125 """) 126 127 t.write("src/dir1/include/file1.h", "file1") 128 t.write("src/dir2/include/file2.h", "file2") 129 t.write("src/dir2/include/nested/file3.h", "file3") 130 t.write("src/dir3/include/nested/file4.h", "file4") 131 132 t.run_build_system() 133 134 t.expect_addition("include/file1.h") 135 t.expect_content("include/file1.h", "file1") 136 t.expect_addition("include/file2.h") 137 t.expect_content("include/file2.h", "file2") 138 t.expect_addition("include/nested/file3.h") 139 t.expect_content("include/nested/file3.h", "file3") 140 t.expect_addition("include/nested/file4.h") 141 t.expect_content("include/nested/file4.h", "file4") 142 ignore_config(t) 143 t.expect_nothing_more() 144 145 t.cleanup() 146 147def test_merge_recursive_existing(group1, group2): 148 "Test merging several directories including common prefixes." 149 t = BoostBuild.Tester() 150 t.write("jamroot.jam", """\ 151 import link ; 152 link-directory dir1-link : src/dir1/include : <location>. ; 153 link-directory dir2-link : src/dir2/include : <location>. ; 154 link-directory dir3-link : src/dir3/include : <location>. ; 155 link-directory dir4-link : src/dir4/include : <location>. ; 156 link-directory dir5-link : src/dir5/include : <location>. ; 157 """) 158 159 t.write("src/dir1/include/file1.h", "file1") 160 t.write("src/dir2/include/nested/file2.h", "file2") 161 t.write("src/dir3/include/nested/file3.h", "file3") 162 t.write("src/dir4/include/nested/xxx/yyy/file4.h", "file4") 163 t.write("src/dir5/include/nested/xxx/yyy/file5.h", "file5") 164 165 t.run_build_system(group1) 166 t.run_build_system(group2 + ["-d+12"]) 167 168 def check_file(target, file): 169 if target in group2: 170 if target in group1: 171 t.ignore_touch(file) 172 else: 173 t.expect_addition(file) 174 175 check_file("dir1-link", "include/file1.h") 176 check_file("dir2-link", "include/nested/file2.h") 177 check_file("dir3-link", "include/nested/file3.h") 178 check_file("dir4-link", "include/nested/xxx/yyy/file4.h") 179 check_file("dir5-link", "include/nested/xxx/yyy/file5.h") 180 ignore_config(t) 181 t.expect_nothing_more() 182 183 t.cleanup() 184 185def test_merge_recursive_existing_all(): 186 # These should create a link 187 test_merge_recursive_existing(["dir2-link"], ["dir2-link", "dir1-link"]) 188 test_merge_recursive_existing(["dir2-link"], ["dir1-link", "dir2-link"]) 189 # These should create a directory 190 test_merge_recursive_existing(["dir2-link"], ["dir2-link", "dir3-link"]) 191 test_merge_recursive_existing(["dir2-link"], ["dir3-link", "dir2-link"]) 192 # It should work even if we have to create many intermediate subdirectories 193 test_merge_recursive_existing(["dir4-link"], ["dir4-link", "dir5-link"]) 194 test_merge_recursive_existing(["dir4-link"], ["dir5-link", "dir4-link"]) 195 196def test_include_scan(): 197 """Make sure that the #include scanner finds the headers""" 198 t = BoostBuild.Tester() 199 t.write("jamroot.jam", """\ 200 import link ; 201 link-directory dir1-link : src/dir1/include : <location>. ; 202 link-directory dir2-link : src/dir2/include : <location>. ; 203 obj test : test.cpp : 204 <include>include 205 <implicit-dependency>dir1-link 206 <implicit-dependency>dir2-link ; 207 """) 208 209 t.write("src/dir1/include/file1.h", "#include <file2.h>\n") 210 t.write("src/dir2/include/file2.h", "int f();\n") 211 t.write("test.cpp", """\ 212 #include <file1.h> 213 int main() { f(); } 214 """); 215 216 t.run_build_system(["test"]) 217 218 t.expect_addition("bin/$toolset/debug*/test.obj") 219 220 t.run_build_system() 221 t.expect_nothing_more() 222 223 t.cleanup() 224 225def test_include_scan_merge_existing(): 226 """Make sure that files are replaced if needed when merging in 227 a new directory""" 228 t = BoostBuild.Tester() 229 230 t.write("jamroot.jam", """\ 231 import link ; 232 link-directory dir1-link : src/dir1/include : <location>. ; 233 link-directory dir2-link : src/dir2/include : <location>. ; 234 obj test : test.cpp : 235 <include>include 236 <implicit-dependency>dir1-link 237 <implicit-dependency>dir2-link ; 238 """) 239 240 t.write("src/dir1/include/file1.h", "int f();") 241 t.write("src/dir2/include/file2.h", "#include <file1.h>") 242 t.write("test.cpp", """\ 243 #include <file2.h> 244 int main() { f(); } 245 """) 246 247 t.run_build_system(["dir2-link"]) 248 249 t.run_build_system(["test"]) 250 t.expect_addition("include/file1.h") 251 t.expect_addition("bin/$toolset/debug*/test.obj") 252 t.ignore_touch("include/file2.h") 253 t.expect_nothing_more() 254 255 t.cleanup() 256 257def test_update_file_link(params1, params2): 258 """Tests the behavior of updates when changing the link mode. 259 The link needs to be updated iff the original was a copy.""" 260 t = BoostBuild.Tester() 261 262 t.write("jamroot.jam", """\ 263 import link ; 264 import project ; 265 import property-set ; 266 import modules ; 267 268 if --no-symlinks in [ modules.peek : ARGV ] 269 { 270 modules.poke link : .can-symlink : false ; 271 } 272 273 if --no-hardlinks in [ modules.peek : ARGV ] 274 { 275 modules.poke link : .can-hardlink : false ; 276 } 277 278 .project = [ project.current ] ; 279 .has-files = [ glob include/file1.h ] ; 280 281 rule can-link ( properties * ) { 282 if ( ! [ link.can-symlink $(.project) ] ) && 283 ( ! [ link.can-hardlink $(.project) ] ) 284 { 285 ECHO links unsupported ; 286 } 287 } 288 289 # Use two directories so that we link to individual files. 290 link-directory dir1-link : src/dir1/include : <location>. ; 291 link-directory dir2-link : src/dir2/include : <location>. ; 292 alias check-linking : : <conditional>@can-link ; 293 """) 294 t.write("src/dir1/include/file1.h", "file1") 295 t.write("src/dir2/include/file2.h", "file2") 296 297 t.run_build_system(params1) 298 ignore_config(t) 299 t.expect_addition("include/file1.h") 300 t.expect_addition("include/file2.h") 301 t.expect_nothing_more() 302 303 using_links = "links unsupported" not in t.stdout() 304 305 t.touch("src/dir1/include/file1.h") 306 307 t.run_build_system(params2) 308 if not using_links: t.expect_touch("include/file1.h") 309 ignore_config(t) 310 t.expect_nothing_more() 311 312 t.cleanup() 313 314def test_update_file_link_all(): 315 """Test all nine possible combinations of two runs.""" 316 possible_args = [[], ["--no-symlinks"], ["--no-symlinks", "--no-hardlinks"]] 317 for arg1 in possible_args: 318 for arg2 in possible_args: 319 test_update_file_link(arg1, arg2) 320 321def test_error_duplicate(): 322 """Test that linking a single file from 323 multiple sources causes a hard error.""" 324 t = BoostBuild.Tester() 325 326 t.write("jamroot.jam", """\ 327 import link ; 328 link-directory dir1-link : src/dir1/include : <location>. ; 329 link-directory dir2-link : src/dir2/include : <location>. ; 330 """) 331 332 t.write("src/dir1/include/file1.h", "file1") 333 t.write("src/dir2/include/file1.h", "file2") 334 335 t.run_build_system(status=1) 336 t.expect_output_lines( 337 ["error: Cannot create link include/file1.h to src/dir2/include/file1.h.", 338 "error: Link previously defined to another file, src/dir1/include/file1.h."]) 339 340 t.cleanup() 341 342test_basic() 343test_merge_two() 344test_merge_existing_all() 345test_merge_recursive() 346test_merge_recursive_existing_all() 347test_include_scan() 348test_include_scan_merge_existing() 349test_update_file_link_all() 350test_error_duplicate() 351