Skip to content

Commit

Permalink
#101: Add test which violates equals contract
Browse files Browse the repository at this point in the history
- Use identity hashmap to check relations for creations
  • Loading branch information
epochcoder committed Nov 21, 2024
1 parent e163a91 commit bc53e84
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand Down Expand Up @@ -92,7 +93,7 @@ public class DefaultResultSetHandler implements ResultSetHandler {
private final ReflectorFactory reflectorFactory;

// pending creations property tracker
private final Map<Object, PendingRelation> pendingPccRelations = new HashMap<>();
private final Map<Object, PendingRelation> pendingPccRelations = new IdentityHashMap<>();

// nested resultmaps
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,40 @@ void testImmutableNestedObjects() {
container.getStores());
}
}

@Test
void testImmutableNestedObjectsWithBadEquals() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Mapper mapper = sqlSession.getMapper(Mapper.class);
List<Container1> containers = mapper.getContainers();

Container1 expectedContainer1 = new Container1();
expectedContainer1.setNum(1);
expectedContainer1.setType("storesWithClerks");
expectedContainer1.setStores(Arrays.asList(
new Store9(1, "Store 1",
Arrays.asList(new Clerk(1001, "Clerk 1001"), new Clerk(1003, "Clerk 1003"),
new Clerk(1004, "Clerk 1004"))),
new Store9(2, "Store 2", Arrays.asList()), new Store9(3, "Store 3", Arrays.asList())));

Container1 expectedContainer2 = new Container1();
expectedContainer2.setNum(1);
expectedContainer2.setType("storesWithManagers");
expectedContainer2.setStores(Arrays.asList(
new Store9(1, "Store 1", Arrays.asList(new Clerk(1002, "Clerk 1002"), new Clerk(1005, "Clerk 1005")))));

// cannot use direct equals as we overwrote it with a bad impl on purpose
org.assertj.core.api.Assertions.assertThat(containers).isNotNull().hasSize(2);
assertContainer1(containers.get(0), expectedContainer1);
assertContainer1(containers.get(1), expectedContainer2);
}
}

private static void assertContainer1(Container1 container1, Container1 expectedContainer1) {
org.assertj.core.api.Assertions.assertThat(container1).isNotNull().satisfies(c -> {
org.assertj.core.api.Assertions.assertThat(c.getNum()).isEqualTo(expectedContainer1.getNum());
org.assertj.core.api.Assertions.assertThat(c.getType()).isEqualTo(expectedContainer1.getType());
org.assertj.core.api.Assertions.assertThat(c.getStores()).isEqualTo(expectedContainer1.getStores());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2009-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.ibatis.submitted.collection_in_constructor;

import java.util.List;
import java.util.Objects;

public class Container1 {

private Integer num;
private String type;
private List<Store9> stores;

public Integer getNum() {
return num;
}

public void setNum(Integer num) {
this.num = num;
}

public List<Store9> getStores() {
return stores;
}

public void setStores(List<Store9> stores) {
this.stores = stores;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

@Override
// simulate a misbehaving object with a bad equals override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Container1 that = (Container1) o;
return Objects.equals(num, that.num);
}

@Override
public int hashCode() {
return Objects.hash(num);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ public interface Mapper {

Container getAContainer();

List<Container1> getContainers();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2009-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.submitted.collection_in_constructor;

import java.util.List;
import java.util.Objects;

public class Store9 {

private final Integer id;
private final String name;
private final List<Clerk> clerks;

public Store9(Integer id, String name, List<Clerk> clerks) {
this.id = id;
this.name = name;
this.clerks = clerks;
}

public Integer getId() {
return id;
}

public String getName() {
return name;
}

public List<Clerk> getClerks() {
return clerks;
}

@Override
public int hashCode() {
return Objects.hash(id);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Store9)) {
return false;
}
Store9 other = (Store9) obj;
return Objects.equals(id, other.id);
}

@Override
public String toString() {
return "Store9 [id=" + id + ", name=" + name + ", clerks=" + clerks + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,45 @@
order by s.id, i.id
]]></select>

</mapper>
<resultMap
type="org.apache.ibatis.submitted.collection_in_constructor.Clerk"
id="immutableClerkRM">
<constructor>
<idArg column="id" javaType="int" />
<arg column="name" javaType="string" />
</constructor>
</resultMap>

<resultMap
type="org.apache.ibatis.submitted.collection_in_constructor.Store9"
id="store9RM">
<constructor>
<idArg column="id" javaType="int" />
<arg column="name" javaType="string" />
<arg javaType="list" resultMap="immutableClerkRM" columnPrefix="clerk_" />
</constructor>
</resultMap>

<resultMap
type="org.apache.ibatis.submitted.collection_in_constructor.Container1"
id="container1RM">
<id column="type" property="type"/>
<result column="num" property="num" />
<collection property="stores" resultMap="store9RM"/>
</resultMap>

<select id="getContainers" resultMap="container1RM"
resultOrdered="true"><![CDATA[
select
1 num
, casewhen(c.is_manager, rtrim('storesWithManagers'), rtrim('storesWithClerks')) as type
, s.id
, s.name
, c.id clerk_id
, c.name clerk_name
from store s
left join clerk c on c.store_id = s.id
order by type, s.id, c.id
]]></select>

</mapper>

0 comments on commit bc53e84

Please sign in to comment.