aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorMarc Tiehuis <marc@tiehu.is>2023-09-01 19:37:40 +1200
committerMarc Tiehuis <marc@tiehu.is>2023-09-02 15:37:49 +1200
commit1c148f161905469b0ad5cf4de801cf287c491174 (patch)
tree702966068829d7775a33e79d734f24bca5eab97d /lib/std
parent26d61812a8dbad204517d00d3a1f0e52275eceeb (diff)
downloadzig-1c148f161905469b0ad5cf4de801cf287c491174.tar.gz
zig-1c148f161905469b0ad5cf4de801cf287c491174.zip
std/hash: add generic tests for idempotency/iterative api
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/hash/adler.zig8
-rw-r--r--lib/std/hash/crc.zig12
-rw-r--r--lib/std/hash/crc/catalog_test.zig2
-rw-r--r--lib/std/hash/fnv.zig5
-rw-r--r--lib/std/hash/verify.zig27
-rw-r--r--lib/std/hash/wyhash.zig47
-rw-r--r--lib/std/hash/xxhash.zig8
7 files changed, 61 insertions, 48 deletions
diff --git a/lib/std/hash/adler.zig b/lib/std/hash/adler.zig
index 200dc9aafe..52f7b2691a 100644
--- a/lib/std/hash/adler.zig
+++ b/lib/std/hash/adler.zig
@@ -3,7 +3,7 @@
// https://tools.ietf.org/html/rfc1950#section-9
// https://github.com/madler/zlib/blob/master/adler32.c
-const std = @import("../std.zig");
+const std = @import("std");
const testing = std.testing;
pub const Adler32 = struct {
@@ -126,3 +126,9 @@ test "adler32 very long with variation" {
try testing.expectEqual(@as(u32, 0x5af38d6e), std.hash.Adler32.hash(long[0..]));
}
+
+const verify = @import("verify.zig");
+
+test "adler32 iterative" {
+ try verify.iterativeApi(Adler32);
+}
diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig
index 9a5936874d..cbd3c75d4d 100644
--- a/lib/std/hash/crc.zig
+++ b/lib/std/hash/crc.zig
@@ -5,7 +5,7 @@
// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
// still moderately fast just slow relative to the slicing approach.
-const std = @import("../std.zig");
+const std = @import("std");
const builtin = @import("builtin");
const debug = std.debug;
const testing = std.testing;
@@ -194,6 +194,8 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type {
};
}
+const verify = @import("verify.zig");
+
test "crc32 ieee" {
const Crc32Ieee = Crc32WithPoly(.IEEE);
@@ -210,6 +212,10 @@ test "crc32 castagnoli" {
try testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
}
+test "crc32 iterative" {
+ try verify.iterativeApi(Crc32WithPoly(.IEEE));
+}
+
// half-byte lookup table implementation.
pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
return struct {
@@ -258,6 +264,10 @@ pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
};
}
+test "small crc32 iterative" {
+ try verify.iterativeApi(Crc32SmallWithPoly(.IEEE));
+}
+
test "small crc32 ieee" {
const Crc32Ieee = Crc32SmallWithPoly(.IEEE);
diff --git a/lib/std/hash/crc/catalog_test.zig b/lib/std/hash/crc/catalog_test.zig
index b9bf21fc99..ab89745ca8 100644
--- a/lib/std/hash/crc/catalog_test.zig
+++ b/lib/std/hash/crc/catalog_test.zig
@@ -1,6 +1,6 @@
//! This file is auto-generated by tools/update_crc_catalog.zig.
-const std = @import("../../std.zig");
+const std = @import("std");
const testing = std.testing;
const catalog = @import("catalog.zig");
diff --git a/lib/std/hash/fnv.zig b/lib/std/hash/fnv.zig
index c95f19c04e..01469bff8a 100644
--- a/lib/std/hash/fnv.zig
+++ b/lib/std/hash/fnv.zig
@@ -40,19 +40,24 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
};
}
+const verify = @import("verify.zig");
+
test "fnv1a-32" {
try testing.expect(Fnv1a_32.hash("") == 0x811c9dc5);
try testing.expect(Fnv1a_32.hash("a") == 0xe40c292c);
try testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968);
+ try verify.iterativeApi(Fnv1a_32);
}
test "fnv1a-64" {
try testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325);
try testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
try testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
+ try verify.iterativeApi(Fnv1a_64);
}
test "fnv1a-128" {
try testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
try testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
+ try verify.iterativeApi(Fnv1a_128);
}
diff --git a/lib/std/hash/verify.zig b/lib/std/hash/verify.zig
index bfc6a1f22c..5d853fee28 100644
--- a/lib/std/hash/verify.zig
+++ b/lib/std/hash/verify.zig
@@ -13,6 +13,15 @@ fn hashMaybeSeed(comptime hash_fn: anytype, seed: anytype, buf: []const u8) @typ
}
}
+fn initMaybeSeed(comptime Hash: anytype, seed: anytype) Hash {
+ const HashFn = @typeInfo(@TypeOf(Hash.init)).Fn;
+ if (HashFn.params.len == 1) {
+ return Hash.init(@intCast(seed));
+ } else {
+ return Hash.init();
+ }
+}
+
// Returns a verification code, the same as user by SMHasher.
//
// Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255, using 256-N as seed.
@@ -33,3 +42,21 @@ pub fn smhasher(comptime hash_fn: anytype) u32 {
return @truncate(hashMaybeSeed(hash_fn, 0, buf_all[0..]));
}
+
+pub fn iterativeApi(comptime Hash: anytype) !void {
+ // Sum(1..32) = 528
+ var buf: [528]u8 = [_]u8{0} ** 528;
+ var len: usize = 0;
+ const seed = 0;
+
+ var hasher = initMaybeSeed(Hash, seed);
+ for (1..32) |i| {
+ const r = hashMaybeSeed(Hash.hash, seed, buf[0 .. len + i]);
+ hasher.update(buf[len..][0..i]);
+ const f1 = hasher.final();
+ const f2 = hasher.final();
+ if (f1 != f2) return error.IterativeHashWasNotIdempotent;
+ if (f1 != r) return error.IterativeHashDidNotMatchDirect;
+ len += i;
+ }
+}
diff --git a/lib/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig
index 741b117f5d..6ceaba696a 100644
--- a/lib/std/hash/wyhash.zig
+++ b/lib/std/hash/wyhash.zig
@@ -234,51 +234,8 @@ test "smhasher" {
try expectEqual(verify.smhasher(Wyhash.hash), 0xBD5E840C);
}
-test "test vectors streaming" {
- const step = 5;
-
- for (vectors) |e| {
- var wh = Wyhash.init(e.seed);
- var i: usize = 0;
- while (i < e.input.len) : (i += step) {
- const len = if (i + step > e.input.len) e.input.len - i else step;
- wh.update(e.input[i..][0..len]);
- }
- try expectEqual(e.expected, wh.final());
- }
-}
-
-test "test ensure idempotent final call" {
- const e: TestVector = .{ .seed = 6, .expected = 0xc39cab13b115aad3, .input = "12345678901234567890123456789012345678901234567890123456789012345678901234567890" };
- var wh = Wyhash.init(e.seed);
- wh.update(e.input);
-
- for (0..10) |_| {
- try expectEqual(e.expected, wh.final());
- }
-}
-
-test "iterative non-divisible update" {
- var buf: [8192]u8 = undefined;
- for (&buf, 0..) |*e, i| {
- e.* = @as(u8, @truncate(i));
- }
-
- const seed = 0x128dad08f;
-
- var end: usize = 32;
- while (end < buf.len) : (end += 32) {
- const non_iterative_hash = Wyhash.hash(seed, buf[0..end]);
-
- var wy = Wyhash.init(seed);
- var i: usize = 0;
- while (i < end) : (i += 33) {
- wy.update(buf[i..@min(i + 33, end)]);
- }
- const iterative_hash = wy.final();
-
- try std.testing.expectEqual(iterative_hash, non_iterative_hash);
- }
+test "iterative api" {
+ try verify.iterativeApi(Wyhash);
}
test "iterative maintains last sixteen" {
diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig
index 6b6208b854..f267f72e6a 100644
--- a/lib/std/hash/xxhash.zig
+++ b/lib/std/hash/xxhash.zig
@@ -461,6 +461,10 @@ test "xxhash64" {
try expectEqual(verify.smhasher(H.hash), 0x024B7CF4);
}
+test "xxhash64 iterative api" {
+ try verify.iterativeApi(XxHash64);
+}
+
test "xxhash32" {
const H = XxHash32;
@@ -474,3 +478,7 @@ test "xxhash32" {
try expectEqual(verify.smhasher(H.hash), 0xBA88B743);
}
+
+test "xxhash32 iterative api" {
+ try verify.iterativeApi(XxHash32);
+}