tint: Add hash randomization

Enable this in Kororo builds to ensure that output isn't dependent on
hash values.

Change-Id: Ib538385b53bebf5260186b14cea396dac15caf6c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/113980
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 27d70f2..1f27535 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -171,6 +171,7 @@
 option_if_not_defined(TINT_ENABLE_BREAK_IN_DEBUGGER "Enable tint::debugger::Break()" OFF)
 option_if_not_defined(TINT_CHECK_CHROMIUM_STYLE "Check for [chromium-style] issues during build" OFF)
 option_if_not_defined(TINT_SYMBOL_STORE_DEBUG_NAME "Enable storing of name in tint::ast::Symbol to help debugging the AST" OFF)
+option_if_not_defined(TINT_RANDOMIZE_HASHES "Randomize the hash seed value to detect non-deterministic output" OFF)
 
 # Recommended setting for compability with future abseil releases.
 set(ABSL_PROPAGATE_CXX_STD ON)
@@ -598,6 +599,15 @@
       )
     endif()
   endif()
+
+  if (TINT_RANDOMIZE_HASHES)
+    if(NOT DEFINED TINT_HASH_SEED)
+        string(RANDOM LENGTH 16 ALPHABET "0123456789abcdef" seed)
+        set(TINT_HASH_SEED "0x${seed}" CACHE STRING "Tint hash seed value")
+        message("Using TINT_HASH_SEED: ${TINT_HASH_SEED}")
+    endif()
+    target_compile_definitions(${TARGET} PUBLIC "-DTINT_HASH_SEED=${TINT_HASH_SEED}")
+  endif()
 endfunction()
 
 ################################################################################
diff --git a/infra/kokoro/linux/docker.sh b/infra/kokoro/linux/docker.sh
index f1145e3..3f92aac 100755
--- a/infra/kokoro/linux/docker.sh
+++ b/infra/kokoro/linux/docker.sh
@@ -129,6 +129,7 @@
     COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_MSL_WRITER=1"
     COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_SPV_WRITER=1"
     COMMON_CMAKE_FLAGS+=" -DTINT_BUILD_WGSL_WRITER=1"
+    COMMON_CMAKE_FLAGS+=" -DTINT_RANDOMIZE_HASHES=1"
 
     if [ "$BUILD_TOOLCHAIN" == "clang" ]; then
         using clang-10.0.0
diff --git a/infra/kokoro/windows/build.bat b/infra/kokoro/windows/build.bat
index 9a355c9..eac0a71 100644
--- a/infra/kokoro/windows/build.bat
+++ b/infra/kokoro/windows/build.bat
@@ -109,7 +109,20 @@
 @echo on
 mkdir %BUILD_DIR%
 cd /d %BUILD_DIR%
-set COMMON_CMAKE_FLAGS=-DTINT_BUILD_DOCS=O -DTINT_BUILD_BENCHMARKS=1 -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DTINT_BUILD_BENCHMARKS=1 -DTINT_BUILD_SPV_READER=1 -DTINT_BUILD_WGSL_READER=1 -DTINT_BUILD_GLSL_WRITER=1 -DTINT_BUILD_HLSL_WRITER=1 -DTINT_BUILD_MSL_WRITER=1 -DTINT_BUILD_SPV_WRITER=1 -DTINT_BUILD_WGSL_WRITER=1
+set COMMON_CMAKE_FLAGS=             ^
+    -DTINT_BUILD_DOCS=O             ^
+    -DTINT_BUILD_BENCHMARKS=1       ^
+    -DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^
+    -DTINT_BUILD_BENCHMARKS=1       ^
+    -DTINT_BUILD_SPV_READER=1       ^
+    -DTINT_BUILD_WGSL_READER=1      ^
+    -DTINT_BUILD_GLSL_WRITER=1      ^
+    -DTINT_BUILD_HLSL_WRITER=1      ^
+    -DTINT_BUILD_MSL_WRITER=1       ^
+    -DTINT_BUILD_SPV_WRITER=1       ^
+    -DTINT_BUILD_WGSL_WRITER=1      ^
+    -DTINT_RANDOMIZE_HASHES=1
+
 @echo off
 
 call :status "Building dawn"
diff --git a/src/tint/sem/struct_test.cc b/src/tint/sem/struct_test.cc
index 8d16c2d..b009d55 100644
--- a/src/tint/sem/struct_test.cc
+++ b/src/tint/sem/struct_test.cc
@@ -34,17 +34,6 @@
     EXPECT_EQ(s->SizeNoPadding(), 16u);
 }
 
-TEST_F(SemStructTest, Hash) {
-    auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
-    auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
-                                  4u /* align */, 4u /* size */, 4u /* size_no_padding */);
-    auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
-    auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, utils::Empty,
-                                  4u /* align */, 4u /* size */, 4u /* size_no_padding */);
-
-    EXPECT_NE(a->Hash(), b->Hash());
-}
-
 TEST_F(SemStructTest, Equals) {
     auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
     auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
diff --git a/src/tint/type/array_test.cc b/src/tint/type/array_test.cc
index 367aa4b..cd4d5f1 100644
--- a/src/tint/type/array_test.cc
+++ b/src/tint/type/array_test.cc
@@ -74,18 +74,8 @@
 TEST_F(ArrayTest, Hash) {
     auto* a = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 32u, 16u);
     auto* b = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 32u, 16u);
-    auto* c = create<Array>(create<U32>(), create<ConstantArrayCount>(3u), 4u, 8u, 32u, 16u);
-    auto* d = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 5u, 8u, 32u, 16u);
-    auto* e = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 9u, 32u, 16u);
-    auto* f = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 33u, 16u);
-    auto* g = create<Array>(create<U32>(), create<ConstantArrayCount>(2u), 4u, 8u, 33u, 17u);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
-    EXPECT_NE(a->Hash(), e->Hash());
-    EXPECT_NE(a->Hash(), f->Hash());
-    EXPECT_NE(a->Hash(), g->Hash());
 }
 
 TEST_F(ArrayTest, Equals) {
diff --git a/src/tint/type/atomic_test.cc b/src/tint/type/atomic_test.cc
index b67e118..740ce79 100644
--- a/src/tint/type/atomic_test.cc
+++ b/src/tint/type/atomic_test.cc
@@ -33,9 +33,7 @@
 TEST_F(AtomicTest, Hash) {
     auto* a = create<Atomic>(create<I32>());
     auto* b = create<Atomic>(create<I32>());
-    auto* c = create<Atomic>(create<U32>());
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
 }
 
 TEST_F(AtomicTest, Equals) {
diff --git a/src/tint/type/depth_texture_test.cc b/src/tint/type/depth_texture_test.cc
index b729dc8..3b73af4 100644
--- a/src/tint/type/depth_texture_test.cc
+++ b/src/tint/type/depth_texture_test.cc
@@ -36,10 +36,8 @@
 TEST_F(DepthTextureTest, Hash) {
     auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
     auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
-    auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
 }
 
 TEST_F(DepthTextureTest, Equals) {
diff --git a/src/tint/type/matrix_test.cc b/src/tint/type/matrix_test.cc
index aff6924..7d88c6a 100644
--- a/src/tint/type/matrix_test.cc
+++ b/src/tint/type/matrix_test.cc
@@ -40,14 +40,8 @@
 TEST_F(MatrixTest, Hash) {
     auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
     auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-    auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
-    auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
-    auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
-    EXPECT_NE(a->Hash(), e->Hash());
 }
 
 TEST_F(MatrixTest, Equals) {
diff --git a/src/tint/type/multisampled_texture_test.cc b/src/tint/type/multisampled_texture_test.cc
index cf3d28a..8eac7c6 100644
--- a/src/tint/type/multisampled_texture_test.cc
+++ b/src/tint/type/multisampled_texture_test.cc
@@ -38,11 +38,7 @@
 TEST_F(MultisampledTextureTest, Hash) {
     auto* a = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
     auto* b = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-    auto* c = create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
-    auto* d = create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
 }
 
 TEST_F(MultisampledTextureTest, Equals) {
diff --git a/src/tint/type/pointer_test.cc b/src/tint/type/pointer_test.cc
index 4f8033f..ab51f7c 100644
--- a/src/tint/type/pointer_test.cc
+++ b/src/tint/type/pointer_test.cc
@@ -40,14 +40,8 @@
 TEST_F(PointerTest, Hash) {
     auto* a = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
     auto* b = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
-    auto* c = create<Pointer>(create<F32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
-    auto* d = create<Pointer>(create<I32>(), ast::AddressSpace::kPrivate, ast::Access::kReadWrite);
-    auto* e = create<Pointer>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kRead);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
-    EXPECT_NE(a->Hash(), e->Hash());
 }
 
 TEST_F(PointerTest, Equals) {
diff --git a/src/tint/type/reference_test.cc b/src/tint/type/reference_test.cc
index 3d50997..094770e 100644
--- a/src/tint/type/reference_test.cc
+++ b/src/tint/type/reference_test.cc
@@ -46,16 +46,8 @@
         create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
     auto* b =
         create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
-    auto* c =
-        create<Reference>(create<F32>(), ast::AddressSpace::kStorage, ast::Access::kReadWrite);
-    auto* d =
-        create<Reference>(create<I32>(), ast::AddressSpace::kPrivate, ast::Access::kReadWrite);
-    auto* e = create<Reference>(create<I32>(), ast::AddressSpace::kStorage, ast::Access::kRead);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
-    EXPECT_NE(a->Hash(), e->Hash());
 }
 
 TEST_F(ReferenceTest, Equals) {
diff --git a/src/tint/type/sampled_texture_test.cc b/src/tint/type/sampled_texture_test.cc
index ab0c74d..f9cb5be 100644
--- a/src/tint/type/sampled_texture_test.cc
+++ b/src/tint/type/sampled_texture_test.cc
@@ -41,12 +41,8 @@
 TEST_F(SampledTextureTest, Hash) {
     auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
     auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-    auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
-    auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
 }
 
 TEST_F(SampledTextureTest, Equals) {
diff --git a/src/tint/type/sampler_test.cc b/src/tint/type/sampler_test.cc
index 65a2370..ba30541 100644
--- a/src/tint/type/sampler_test.cc
+++ b/src/tint/type/sampler_test.cc
@@ -39,10 +39,8 @@
 TEST_F(SamplerTest, Hash) {
     auto* a = create<Sampler>(ast::SamplerKind::kSampler);
     auto* b = create<Sampler>(ast::SamplerKind::kSampler);
-    auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
 }
 
 TEST_F(SamplerTest, Equals) {
diff --git a/src/tint/type/storage_texture_test.cc b/src/tint/type/storage_texture_test.cc
index b375207..0c86d89 100644
--- a/src/tint/type/storage_texture_test.cc
+++ b/src/tint/type/storage_texture_test.cc
@@ -55,17 +55,8 @@
                      ast::Access::kReadWrite);
     auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
                      ast::Access::kReadWrite);
-    auto* c =
-        Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
-    auto* d =
-        Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float, ast::Access::kReadWrite);
-    auto* e =
-        Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, ast::Access::kRead);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
-    EXPECT_NE(a->Hash(), e->Hash());
 }
 
 TEST_F(StorageTextureTest, Equals) {
diff --git a/src/tint/type/struct_test.cc b/src/tint/type/struct_test.cc
index ae9a249..8bacfca 100644
--- a/src/tint/type/struct_test.cc
+++ b/src/tint/type/struct_test.cc
@@ -31,15 +31,6 @@
     EXPECT_EQ(s->SizeNoPadding(), 16u);
 }
 
-TEST_F(TypeStructTest, Hash) {
-    auto* a = create<Struct>(Source{}, Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
-                             4u /* size_no_padding */);
-    auto* b = create<Struct>(Source{}, Sym("b"), utils::Empty, 4u /* align */, 4u /* size */,
-                             4u /* size_no_padding */);
-
-    EXPECT_NE(a->Hash(), b->Hash());
-}
-
 TEST_F(TypeStructTest, Equals) {
     auto* a = create<Struct>(Source{}, Sym("a"), utils::Empty, 4u /* align */, 4u /* size */,
                              4u /* size_no_padding */);
diff --git a/src/tint/type/vector_test.cc b/src/tint/type/vector_test.cc
index aed294a..65d7b1b 100644
--- a/src/tint/type/vector_test.cc
+++ b/src/tint/type/vector_test.cc
@@ -37,12 +37,8 @@
 TEST_F(VectorTest, Hash) {
     auto* a = create<Vector>(create<I32>(), 2u);
     auto* b = create<Vector>(create<I32>(), 2u);
-    auto* c = create<Vector>(create<F32>(), 2u);
-    auto* d = create<Vector>(create<F32>(), 3u);
 
     EXPECT_EQ(a->Hash(), b->Hash());
-    EXPECT_NE(a->Hash(), c->Hash());
-    EXPECT_NE(a->Hash(), d->Hash());
 }
 
 TEST_F(VectorTest, Equals) {
diff --git a/src/tint/utils/enum_set_test.cc b/src/tint/utils/enum_set_test.cc
index e469650..4cdeb63 100644
--- a/src/tint/utils/enum_set_test.cc
+++ b/src/tint/utils/enum_set_test.cc
@@ -192,7 +192,6 @@
 TEST(EnumSetTest, Hash) {
     auto hash = [&](EnumSet<E> s) { return std::hash<EnumSet<E>>()(s); };
     EXPECT_EQ(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::B)));
-    EXPECT_NE(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::C)));
 }
 
 TEST(EnumSetTest, Value) {
diff --git a/src/tint/utils/hash.h b/src/tint/utils/hash.h
index 89cf0f0..196861b 100644
--- a/src/tint/utils/hash.h
+++ b/src/tint/utils/hash.h
@@ -23,6 +23,7 @@
 #include <variant>
 #include <vector>
 
+#include "src/tint/utils/crc32.h"
 #include "src/tint/utils/vector.h"
 
 namespace tint::utils {
@@ -37,14 +38,26 @@
 template <>
 struct HashCombineOffset<4> {
     /// @returns the seed bias value for HashCombine()
-    static constexpr inline uint32_t value() { return 0x7f4a7c16; }
+    static constexpr inline uint32_t value() {
+        constexpr uint32_t base = 0x7f4a7c16;
+#ifdef TINT_HASH_SEED
+        return base ^ static_cast<uint32_t>(TINT_HASH_SEED);
+#endif
+        return base;
+    }
 };
 
 /// Specialization of HashCombineOffset for size_t == 8.
 template <>
 struct HashCombineOffset<8> {
     /// @returns the seed bias value for HashCombine()
-    static constexpr inline uint64_t value() { return 0x9e3779b97f4a7c16; }
+    static constexpr inline uint64_t value() {
+        constexpr uint64_t base = 0x9e3779b97f4a7c16;
+#ifdef TINT_HASH_SEED
+        return base ^ static_cast<uint64_t>(TINT_HASH_SEED);
+#endif
+        return base;
+    }
 };
 
 }  // namespace detail
@@ -76,6 +89,9 @@
     /// @returns a hash of the pointer
     size_t operator()(T* ptr) const {
         auto hash = std::hash<T*>()(ptr);
+#ifdef TINT_HASH_SEED
+        hash ^= static_cast<uint32_t>(TINT_HASH_SEED);
+#endif
         return hash ^ (hash >> 4);
     }
 };
diff --git a/src/tint/utils/hash_test.cc b/src/tint/utils/hash_test.cc
index 6ce6820..cdceab4 100644
--- a/src/tint/utils/hash_test.cc
+++ b/src/tint/utils/hash_test.cc
@@ -26,28 +26,19 @@
 
 TEST(HashTests, Basic) {
     EXPECT_EQ(Hash(123), Hash(123));
-    EXPECT_NE(Hash(123), Hash(321));
     EXPECT_EQ(Hash(123, 456), Hash(123, 456));
-    EXPECT_NE(Hash(123, 456), Hash(456, 123));
-    EXPECT_NE(Hash(123, 456), Hash(123));
     EXPECT_EQ(Hash(123, 456, false), Hash(123, 456, false));
-    EXPECT_NE(Hash(123, 456, false), Hash(123, 456));
     EXPECT_EQ(Hash(std::string("hello")), Hash(std::string("hello")));
-    EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
 }
 
 TEST(HashTests, StdVector) {
     EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
     EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3})));
-    EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 4})));
-    EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3, 4})));
 }
 
 TEST(HashTests, TintVector) {
     EXPECT_EQ(Hash(Vector<int, 0>({})), Hash(Vector<int, 0>({})));
     EXPECT_EQ(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3})));
-    EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 4})));
-    EXPECT_NE(Hash(Vector<int, 0>({1, 2, 3})), Hash(Vector<int, 0>({1, 2, 3, 4})));
     EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 4>({1, 2, 3})));
     EXPECT_EQ(Hash(Vector<int, 3>({1, 2, 3})), Hash(Vector<int, 2>({1, 2, 3})));
 }
@@ -55,8 +46,6 @@
 TEST(HashTests, Tuple) {
     EXPECT_EQ(Hash(std::make_tuple(1)), Hash(std::make_tuple(1)));
     EXPECT_EQ(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 3)));
-    EXPECT_NE(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 4)));
-    EXPECT_NE(Hash(std::make_tuple(1, 2, 3)), Hash(std::make_tuple(1, 2, 3, 4)));
 }
 
 TEST(HashTests, UnorderedKeyWrapper) {
diff --git a/src/tint/utils/hashmap_test.cc b/src/tint/utils/hashmap_test.cc
index 5e97aef..6d993e2 100644
--- a/src/tint/utils/hashmap_test.cc
+++ b/src/tint/utils/hashmap_test.cc
@@ -388,11 +388,8 @@
     Hashmap<int, std::string, 8> b;
     EXPECT_EQ(Hash(a), Hash(b));
     a.Add(1, "one");
-    EXPECT_NE(Hash(a), Hash(b));
     b.Add(2, "two");
-    EXPECT_NE(Hash(a), Hash(b));
     a.Add(2, "two");
-    EXPECT_NE(Hash(a), Hash(b));
     b.Add(1, "one");
     EXPECT_EQ(Hash(a), Hash(b));
 }
@@ -402,11 +399,8 @@
     Hashmap<int, std::string, 4> b;
     EXPECT_EQ(Hash(a), Hash(b));
     a.Add(1, "one");
-    EXPECT_NE(Hash(a), Hash(b));
     b.Add(2, "two");
-    EXPECT_NE(Hash(a), Hash(b));
     a.Add(2, "two");
-    EXPECT_NE(Hash(a), Hash(b));
     b.Add(1, "one");
     EXPECT_EQ(Hash(a), Hash(b));
 }