From 0965e96f09b3fda81cf9d41d662e8858321b7f5f Mon Sep 17 00:00:00 2001 From: anish k Date: Thu, 23 Apr 2026 16:46:57 +0000 Subject: [PATCH 1/2] test(spanner): replace fixed hashCode value assertions with contract-compliance tests in OptionsTest `OptionsTest` contained four assertions that verified `Options#hashCode()` returns specific fixed integer values (31, 108027089, -2118248262). The Java `hashCode()` contract does not guarantee cross-JVM or cross-version stability of hash values, so testing against hardcoded numbers is brittle and misleads readers into thinking fixed values are part of the API contract. Signed-off-by: anish k --- .../com/google/cloud/spanner/OptionsTest.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java index 5bd594e83c12..96b5fd2239e2 100644 --- a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java +++ b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java @@ -152,7 +152,11 @@ public void allOptionsAbsent() { assertThat(options.equals(null)).isFalse(); assertThat(options.equals(this)).isFalse(); assertNull(options.isolationLevel()); - assertThat(options.hashCode()).isEqualTo(31); + // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + Options options2 = Options.fromReadOptions(); + assertThat(options.equals(options2)).isTrue(); + assertThat(options.hashCode()).isEqualTo(options2.hashCode()); + assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -175,7 +179,13 @@ public void listOptionsTest() { assertThat(options.pageSize()).isEqualTo(pageSize); assertThat(options.pageToken()).isEqualTo(pageToken); assertThat(options.filter()).isEqualTo(filter); - assertThat(options.hashCode()).isEqualTo(108027089); + // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + Options options2 = + Options.fromListOptions( + Options.pageSize(pageSize), Options.pageToken(pageToken), Options.filter(filter)); + assertThat(options.equals(options2)).isTrue(); + assertThat(options.hashCode()).isEqualTo(options2.hashCode()); + assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -696,7 +706,11 @@ public void updateOptionsTest() { assertEquals("tag: " + tag + " ", options.toString()); assertTrue(options.hasTag()); assertThat(options.tag()).isEqualTo(tag); - assertThat(options.hashCode()).isEqualTo(-2118248262); + // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + Options options2 = Options.fromUpdateOptions(Options.tag(tag)); + assertThat(options.equals(options2)).isTrue(); + assertThat(options.hashCode()).isEqualTo(options2.hashCode()); + assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -728,7 +742,11 @@ public void transactionOptionsTest() { assertEquals("tag: " + tag + " ", options.toString()); assertTrue(options.hasTag()); assertThat(options.tag()).isEqualTo(tag); - assertThat(options.hashCode()).isEqualTo(-2118248262); + // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + Options options2 = Options.fromTransactionOptions(Options.tag(tag)); + assertThat(options.equals(options2)).isTrue(); + assertThat(options.hashCode()).isEqualTo(options2.hashCode()); + assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test From c957a44c719898a94c2d55efe19a9688464fffd0 Mon Sep 17 00:00:00 2001 From: Anish Kataria Date: Mon, 27 Apr 2026 19:42:23 -0400 Subject: [PATCH 2/2] test: remove tautological hashCode assertions and use idiomatic isEqualTo - Remove self-comparing hashCode assertions (always true) - Use assertThat(options).isEqualTo(options2) instead of assertThat(options.equals(options2)).isTrue() for better error messages --- .../com/google/cloud/spanner/OptionsTest.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java index 96b5fd2239e2..24ae7bf4e12a 100644 --- a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java +++ b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java @@ -152,11 +152,10 @@ public void allOptionsAbsent() { assertThat(options.equals(null)).isFalse(); assertThat(options.equals(this)).isFalse(); assertNull(options.isolationLevel()); - // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + // Verify hashCode contract: equal objects must have equal hashCodes. Options options2 = Options.fromReadOptions(); - assertThat(options.equals(options2)).isTrue(); + assertThat(options).isEqualTo(options2); assertThat(options.hashCode()).isEqualTo(options2.hashCode()); - assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -179,13 +178,12 @@ public void listOptionsTest() { assertThat(options.pageSize()).isEqualTo(pageSize); assertThat(options.pageToken()).isEqualTo(pageToken); assertThat(options.filter()).isEqualTo(filter); - // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + // Verify hashCode contract: equal objects must have equal hashCodes. Options options2 = Options.fromListOptions( Options.pageSize(pageSize), Options.pageToken(pageToken), Options.filter(filter)); - assertThat(options.equals(options2)).isTrue(); + assertThat(options).isEqualTo(options2); assertThat(options.hashCode()).isEqualTo(options2.hashCode()); - assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -706,11 +704,10 @@ public void updateOptionsTest() { assertEquals("tag: " + tag + " ", options.toString()); assertTrue(options.hasTag()); assertThat(options.tag()).isEqualTo(tag); - // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + // Verify hashCode contract: equal objects must have equal hashCodes. Options options2 = Options.fromUpdateOptions(Options.tag(tag)); - assertThat(options.equals(options2)).isTrue(); + assertThat(options).isEqualTo(options2); assertThat(options.hashCode()).isEqualTo(options2.hashCode()); - assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test @@ -742,11 +739,10 @@ public void transactionOptionsTest() { assertEquals("tag: " + tag + " ", options.toString()); assertTrue(options.hasTag()); assertThat(options.tag()).isEqualTo(tag); - // Verify hashCode contract: equal objects must have equal hashCodes, and hashCode is stable. + // Verify hashCode contract: equal objects must have equal hashCodes. Options options2 = Options.fromTransactionOptions(Options.tag(tag)); - assertThat(options.equals(options2)).isTrue(); + assertThat(options).isEqualTo(options2); assertThat(options.hashCode()).isEqualTo(options2.hashCode()); - assertThat(options.hashCode()).isEqualTo(options.hashCode()); } @Test