@@ -422,7 +422,7 @@ def test_combining_corrupt_data(self):
422422 self .make_file (".coverage.foo" , """La la la, this isn't coverage data!""" )
423423 cov = coverage .Coverage ()
424424 warning_regex = (
425- r"Couldn't use data file '.*\.coverage\.foo': file (is encrypted or )? is not a database"
425+ r"Couldn't use data file '.*\.coverage\.foo': file is not a database"
426426 )
427427 with self .assert_warnings (cov , [warning_regex ]):
428428 cov .combine ()
@@ -1234,3 +1234,189 @@ def test_combine_no_suffix_multiprocessing(self):
12341234 cov .save ()
12351235 self .assert_file_count (".coverage.*" , 0 )
12361236 self .assert_exists (".coverage" )
1237+
1238+
1239+ class CombiningTest (CoverageTest ):
1240+ """More tests of combining data."""
1241+
1242+ B_LINES = {"b_or_c.py" : [1 , 2 , 3 , 4 , 8 , 9 ]}
1243+ C_LINES = {"b_or_c.py" : [1 , 2 , 3 , 6 , 7 , 8 , 9 ]}
1244+
1245+ def make_b_or_c_py (self ):
1246+ """Create b_or_c.py, used in a few of these tests."""
1247+ # "b_or_c.py b" will run 6 lines.
1248+ # "b_or_c.py c" will run 7 lines.
1249+ # Together, they run 8 lines.
1250+ self .make_file ("b_or_c.py" , """\
1251+ import sys
1252+ a = 2
1253+ if sys.argv[1] == 'b':
1254+ b = 4
1255+ else:
1256+ c = 6
1257+ c2 = 7
1258+ d = 8
1259+ print('done')
1260+ """ )
1261+
1262+ def test_combine_parallel_data (self ):
1263+ self .make_b_or_c_py ()
1264+ self .make_data_file (".coverage.b" , lines = self .B_LINES )
1265+ self .make_data_file (".coverage.c" , lines = self .C_LINES )
1266+
1267+ # Combine the parallel coverage data files into .coverage .
1268+ cov = coverage .Coverage ()
1269+ cov .combine (strict = True )
1270+ self .assert_exists (".coverage" )
1271+
1272+ # After combining, there should be only the .coverage file.
1273+ self .assert_file_count (".coverage.*" , 0 )
1274+
1275+ # Read the coverage file and see that b_or_c.py has all 8 lines
1276+ # executed.
1277+ data = coverage .CoverageData ()
1278+ data .read ()
1279+ assert line_counts (data )['b_or_c.py' ] == 8
1280+
1281+ # Running combine again should fail, because there are no parallel data
1282+ # files to combine.
1283+ cov = coverage .Coverage ()
1284+ with pytest .raises (NoDataError , match = r"No data to combine" ):
1285+ cov .combine (strict = True )
1286+
1287+ # And the originally combined data is still there.
1288+ data = coverage .CoverageData ()
1289+ data .read ()
1290+ assert line_counts (data )['b_or_c.py' ] == 8
1291+
1292+ def test_combine_parallel_data_with_a_corrupt_file (self ):
1293+ self .make_b_or_c_py ()
1294+ self .make_data_file (".coverage.b" , lines = self .B_LINES )
1295+ self .make_data_file (".coverage.c" , lines = self .C_LINES )
1296+
1297+ # Make a bogus data file.
1298+ self .make_file (".coverage.bad" , "This isn't a coverage data file." )
1299+
1300+ # Combine the parallel coverage data files into .coverage .
1301+ cov = coverage .Coverage ()
1302+ with pytest .warns (Warning ) as warns :
1303+ cov .combine (strict = True )
1304+ assert_coverage_warnings (
1305+ warns ,
1306+ re .compile (
1307+ r"Couldn't use data file '.*[/\\]\.coverage\.bad': file is not a database"
1308+ ),
1309+ )
1310+
1311+ # After combining, those two should be the only data files.
1312+ self .assert_exists (".coverage" )
1313+ self .assert_exists (".coverage.bad" )
1314+ self .assert_file_count (".coverage.*" , 1 )
1315+
1316+ # Read the coverage file and see that b_or_c.py has all 8 lines
1317+ # executed.
1318+ data = coverage .CoverageData ()
1319+ data .read ()
1320+ assert line_counts (data )['b_or_c.py' ] == 8
1321+
1322+ def test_combine_no_usable_files (self ):
1323+ # https://github.com/nedbat/coveragepy/issues/629
1324+ self .make_b_or_c_py ()
1325+ self .make_data_file (".coverage" , lines = self .B_LINES )
1326+
1327+ # Make bogus data files.
1328+ self .make_file (".coverage.bad1" , "This isn't a coverage data file." )
1329+ self .make_file (".coverage.bad2" , "This isn't a coverage data file." )
1330+
1331+ # Combine the parallel coverage data files into .coverage, but nothing is readable.
1332+ cov = coverage .Coverage ()
1333+ with pytest .warns (Warning ) as warns :
1334+ with pytest .raises (NoDataError , match = r"No usable data files" ):
1335+ cov .combine (strict = True )
1336+
1337+ warn_rx = re .compile (
1338+ r"Couldn't use data file '.*[/\\]\.coverage\.bad[12]': file is not a database"
1339+ )
1340+ assert_coverage_warnings (warns , warn_rx , warn_rx )
1341+
1342+ # After combining, we should have a main file and two parallel files.
1343+ self .assert_exists (".coverage" )
1344+ self .assert_exists (".coverage.bad1" )
1345+ self .assert_exists (".coverage.bad2" )
1346+ self .assert_file_count (".coverage.*" , 2 )
1347+
1348+ # Read the coverage file and see that b_or_c.py has 6 lines
1349+ # executed (we only did b, not c).
1350+ data = coverage .CoverageData ()
1351+ data .read ()
1352+ assert line_counts (data )['b_or_c.py' ] == 6
1353+
1354+ def test_combine_parallel_data_in_two_steps (self ):
1355+ self .make_b_or_c_py ()
1356+ self .make_data_file (".coverage.b" , lines = self .B_LINES )
1357+
1358+ # Combine the (one) parallel coverage data file into .coverage .
1359+ cov = coverage .Coverage ()
1360+ cov .combine (strict = True )
1361+
1362+ self .assert_exists (".coverage" )
1363+ self .assert_file_count (".coverage.*" , 0 )
1364+
1365+ self .make_data_file (".coverage.c" , lines = self .C_LINES )
1366+ self .assert_exists (".coverage" )
1367+ self .assert_file_count (".coverage.*" , 1 )
1368+
1369+ # Combine the parallel coverage data files into .coverage .
1370+ cov = coverage .Coverage ()
1371+ cov .load ()
1372+ cov .combine (strict = True )
1373+
1374+ # After combining, there should be only the .coverage file.
1375+ self .assert_exists (".coverage" )
1376+ self .assert_file_count (".coverage.*" , 0 )
1377+
1378+ # Read the coverage file and see that b_or_c.py has all 8 lines
1379+ # executed.
1380+ data = coverage .CoverageData ()
1381+ data .read ()
1382+ assert line_counts (data )['b_or_c.py' ] == 8
1383+
1384+ def test_combine_parallel_data_no_append (self ):
1385+ self .make_b_or_c_py ()
1386+ self .make_data_file (".coverage.b" , lines = self .B_LINES )
1387+
1388+ # Combine the (one) parallel coverage data file into .coverage .
1389+ cov = coverage .Coverage ()
1390+ cov .combine (strict = True )
1391+ self .assert_exists (".coverage" )
1392+ self .assert_file_count (".coverage.*" , 0 )
1393+
1394+ self .make_data_file (".coverage.c" , lines = self .C_LINES )
1395+
1396+ # Combine the parallel coverage data files into .coverage, but don't
1397+ # use the data in .coverage already.
1398+ cov = coverage .Coverage ()
1399+ cov .combine (strict = True )
1400+
1401+ # After combining, there should be only the .coverage file.
1402+ self .assert_exists (".coverage" )
1403+ self .assert_file_count (".coverage.*" , 0 )
1404+
1405+ # Read the coverage file and see that b_or_c.py has only 7 lines
1406+ # because we didn't keep the data from running b.
1407+ data = coverage .CoverageData ()
1408+ data .read ()
1409+ assert line_counts (data )['b_or_c.py' ] == 7
1410+
1411+ def test_combine_parallel_data_keep (self ):
1412+ self .make_b_or_c_py ()
1413+ self .make_data_file (".coverage.b" , lines = self .B_LINES )
1414+ self .make_data_file (".coverage.c" , lines = self .C_LINES )
1415+
1416+ # Combine the parallel coverage data files into .coverage with the keep flag.
1417+ cov = coverage .Coverage ()
1418+ cov .combine (strict = True , keep = True )
1419+
1420+ # After combining, the .coverage file & the original combined file should still be there.
1421+ self .assert_exists (".coverage" )
1422+ self .assert_file_count (".coverage.*" , 2 )
0 commit comments