| ... | @@ -1337,3 +1337,173 @@ fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void { | ... | @@ -1337,3 +1337,173 @@ fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void { |
| 1337 | ni = node.next; | 1337 | ni = node.next; |
| 1338 | } | 1338 | } |
| 1339 | } | 1339 | } |
| | 1340 | |
| | 1341 | const testing = std.testing; |
| | 1342 | fn testVerifyContent(mf: *@This(), ni: Node.Index, value: u8, init_len: usize) !void { |
| | 1343 | // Not using std.mem.allEqual, so we can get useful output |
| | 1344 | const slice = ni.slice(mf); |
| | 1345 | var buf: [256]u8 = undefined; |
| | 1346 | @memset(buf[0..init_len], value); |
| | 1347 | @memset(buf[init_len..], 0); |
| | 1348 | try testing.expectEqualSlices(u8, buf[0..slice.len], slice); |
| | 1349 | } |
| | 1350 | |
| | 1351 | test { |
| | 1352 | const gpa = testing.allocator; |
| | 1353 | |
| | 1354 | var tmp_dir = testing.tmpDir(.{}); |
| | 1355 | defer tmp_dir.cleanup(); |
| | 1356 | |
| | 1357 | var file = try tmp_dir.dir.createFile(testing.io, "test.mf", .{ .read = true }); |
| | 1358 | defer file.close(testing.io); |
| | 1359 | |
| | 1360 | var mf = try init(file, gpa, testing.io); |
| | 1361 | defer mf.deinit(gpa); |
| | 1362 | |
| | 1363 | const a = try mf.addFirstChildNode(gpa, .root, .{ .fixed = true, .alignment = .@"4" }); |
| | 1364 | const c = try mf.addLastChildNode(gpa, .root, .{ .fixed = true, .alignment = .@"4" }); |
| | 1365 | const b = try mf.addNodeAfter(gpa, a, .{ .fixed = true, .alignment = .@"4" }); |
| | 1366 | const d = try mf.addNodeAfter(gpa, b, .{ .alignment = .@"4" }); |
| | 1367 | |
| | 1368 | const a_init_size = 8; |
| | 1369 | const b_init_size = 16; |
| | 1370 | const c_init_size = 24; |
| | 1371 | const d_init_size = 28; |
| | 1372 | |
| | 1373 | // Resize without content |
| | 1374 | { |
| | 1375 | // Verify size is aligned forward |
| | 1376 | try d.resize(&mf, gpa, d_init_size - 1); |
| | 1377 | try a.resize(&mf, gpa, a_init_size - 2); |
| | 1378 | try c.resize(&mf, gpa, c_init_size); |
| | 1379 | try b.resize(&mf, gpa, b_init_size); |
| | 1380 | mf.verify(); |
| | 1381 | |
| | 1382 | const a_loc, const a_size = a.location(&mf).resolve(&mf); |
| | 1383 | const b_loc, const b_size = b.location(&mf).resolve(&mf); |
| | 1384 | const c_loc, const c_size = c.location(&mf).resolve(&mf); |
| | 1385 | _, const d_size = d.location(&mf).resolve(&mf); |
| | 1386 | try testing.expect(a_size >= a_init_size); |
| | 1387 | try testing.expect(b_size >= b_init_size); |
| | 1388 | try testing.expect(c_size >= c_init_size); |
| | 1389 | try testing.expect(d_size >= d_init_size); |
| | 1390 | try testing.expect(b_loc >= a_loc + a_size); |
| | 1391 | try testing.expect(c_loc >= b_loc + b_size); |
| | 1392 | } |
| | 1393 | |
| | 1394 | const a_exp_size = 24; |
| | 1395 | const b_exp_size = 28; |
| | 1396 | const c_exp_size = 48; |
| | 1397 | const d_exp_size = 32; |
| | 1398 | |
| | 1399 | // Resize with content |
| | 1400 | { |
| | 1401 | @memset(a.slice(&mf)[0..a_init_size], 0xaa); |
| | 1402 | @memset(b.slice(&mf)[0..b_init_size], 0xbb); |
| | 1403 | @memset(c.slice(&mf)[0..c_init_size], 0xcc); |
| | 1404 | @memset(d.slice(&mf)[0..d_init_size], 0xdd); |
| | 1405 | |
| | 1406 | try a.resize(&mf, gpa, a_exp_size); |
| | 1407 | try b.resize(&mf, gpa, b_exp_size); |
| | 1408 | try c.resize(&mf, gpa, c_exp_size); |
| | 1409 | try d.resize(&mf, gpa, d_exp_size); |
| | 1410 | mf.verify(); |
| | 1411 | |
| | 1412 | const a_loc, const a_size = a.location(&mf).resolve(&mf); |
| | 1413 | const b_loc, const b_size = b.location(&mf).resolve(&mf); |
| | 1414 | const c_loc, const c_size = c.location(&mf).resolve(&mf); |
| | 1415 | _, const d_size = d.location(&mf).resolve(&mf); |
| | 1416 | try testing.expect(a_size >= a_exp_size); |
| | 1417 | try testing.expect(b_size >= b_exp_size); |
| | 1418 | try testing.expect(c_size >= c_exp_size); |
| | 1419 | try testing.expect(d_size >= d_exp_size); |
| | 1420 | try testing.expect(b_loc >= a_loc + a_size); |
| | 1421 | try testing.expect(c_loc >= b_loc + b_size); |
| | 1422 | |
| | 1423 | try testVerifyContent(&mf, a, 0xaa, a_init_size); |
| | 1424 | try testVerifyContent(&mf, b, 0xbb, b_init_size); |
| | 1425 | try testVerifyContent(&mf, c, 0xcc, c_init_size); |
| | 1426 | try testVerifyContent(&mf, d, 0xdd, d_init_size); |
| | 1427 | } |
| | 1428 | |
| | 1429 | // Re-align nodes |
| | 1430 | { |
| | 1431 | try b.realign(&mf, gpa, .@"8", true); |
| | 1432 | try a.realign(&mf, gpa, .@"16", true); |
| | 1433 | mf.verify(); |
| | 1434 | |
| | 1435 | try testVerifyContent(&mf, a, 0xaa, a_init_size); |
| | 1436 | try testVerifyContent(&mf, b, 0xbb, b_init_size); |
| | 1437 | try testVerifyContent(&mf, c, 0xcc, c_init_size); |
| | 1438 | try testVerifyContent(&mf, d, 0xdd, d_init_size); |
| | 1439 | } |
| | 1440 | |
| | 1441 | const child_init: []const struct { std.mem.Alignment, usize } = &.{ |
| | 1442 | .{ .@"8", 16 }, |
| | 1443 | .{ .@"1", 1 }, |
| | 1444 | .{ .@"1", 19 }, |
| | 1445 | .{ .@"1", 3 }, |
| | 1446 | .{ .@"4", 30 }, |
| | 1447 | .{ .@"2", 5 }, |
| | 1448 | .{ .@"16", 60 }, |
| | 1449 | .{ .@"2", 2 }, |
| | 1450 | .{ .@"16", 32 }, |
| | 1451 | }; |
| | 1452 | |
| | 1453 | var children: [child_init.len]Node.Index = undefined; |
| | 1454 | |
| | 1455 | // Differently-aligned fixed sibling nodes |
| | 1456 | { |
| | 1457 | for (children[0 .. children.len - 1], child_init[0 .. children.len - 1], 0..) |*ni, opts, i| { |
| | 1458 | ni.* = try mf.addLastChildNode(gpa, b, .{ |
| | 1459 | .alignment = opts.@"0", |
| | 1460 | .size = opts.@"1", |
| | 1461 | .fixed = true, |
| | 1462 | }); |
| | 1463 | |
| | 1464 | @memset(ni.slice(&mf)[0..opts.@"1"], @intCast(i + 1)); |
| | 1465 | } |
| | 1466 | // Shift differenntly-aligned nodes |
| | 1467 | children[children.len - 1] = try mf.addNodeAfter(gpa, children[3], .{ |
| | 1468 | .alignment = child_init[children.len - 1].@"0", |
| | 1469 | .size = child_init[children.len - 1].@"1", |
| | 1470 | .fixed = true, |
| | 1471 | }); |
| | 1472 | @memset(children[children.len - 1].slice(&mf), @intCast(children.len)); |
| | 1473 | |
| | 1474 | mf.verify(); |
| | 1475 | for (children, child_init, 0..) |ni, opts, i| { |
| | 1476 | try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); |
| | 1477 | } |
| | 1478 | } |
| | 1479 | |
| | 1480 | // Shifting child nodes forward due via resize of parent.prev |
| | 1481 | { |
| | 1482 | try testing.expect(a.location(&mf).resolve(&mf)[1] < 64); |
| | 1483 | try a.resize(&mf, gpa, 64); |
| | 1484 | |
| | 1485 | try testVerifyContent(&mf, a, 0xaa, a_init_size); |
| | 1486 | try testVerifyContent(&mf, c, 0xcc, c_init_size); |
| | 1487 | try testVerifyContent(&mf, d, 0xdd, d_init_size); |
| | 1488 | for (children, child_init, 0..) |ni, opts, i| { |
| | 1489 | try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); |
| | 1490 | } |
| | 1491 | } |
| | 1492 | |
| | 1493 | // Shrink and shift start of trailing node into free space |
| | 1494 | { |
| | 1495 | try mf.shrinkNode(gpa, a, 16, true); |
| | 1496 | mf.verify(); |
| | 1497 | |
| | 1498 | const a_loc, const a_size = a.location(&mf).resolve(&mf); |
| | 1499 | const b_loc, _ = b.location(&mf).resolve(&mf); |
| | 1500 | try testing.expectEqual(b_loc, a_loc + a_size); |
| | 1501 | |
| | 1502 | try testVerifyContent(&mf, a, 0xaa, a_init_size); |
| | 1503 | try testVerifyContent(&mf, c, 0xcc, c_init_size); |
| | 1504 | try testVerifyContent(&mf, d, 0xdd, d_init_size); |
| | 1505 | for (children, child_init, 0..) |ni, opts, i| { |
| | 1506 | try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); |
| | 1507 | } |
| | 1508 | } |
| | 1509 | } |