package fr.openwide.core.test.wicket.more.bindable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.Map; import org.junit.Test; import com.google.common.collect.ImmutableMap; import fr.openwide.core.commons.util.functional.Suppliers2; import fr.openwide.core.wicket.more.bindable.model.BindableModel; import fr.openwide.core.wicket.more.bindable.model.IBindableMapModel; import fr.openwide.core.wicket.more.bindable.model.IBindableModel; public class TestBindableMapModel extends AbstractTestBindableModel { @Test public void alwaysReturnsSameModelInstance() { doReturn(rootValue).when(rootModel).getObject(); IBindableModel<RootValue> bindableModel = new BindableModel<>(rootModel); IBindableModel<?> firstCall = bindableModel.bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); IBindableModel<?> secondCall = bindableModel.bindMapAlreadyAdded(rootBinding().mapProperty()); assertSame(firstCall, secondCall); IBindableModel<?> thirdCall = bindableModel.bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); assertSame(firstCall, thirdCall); } @Test public void alwaysReturnsSameModelInstanceEvenIfChained() { doReturn(rootValue).when(rootModel).getObject(); IBindableModel<RootValue> bindableModel = new BindableModel<>(rootModel); IBindableModel<?> directCall = bindableModel.bindMapWithCache( rootBinding().compositeProperty().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); IBindableModel<?> chainedCall = bindableModel.bind(rootBinding().compositeProperty()) .bindMapAlreadyAdded(rootBinding().mapProperty()); assertSame(directCall, chainedCall); IBindableModel<?> chainedCallWithCache = bindableModel.bind(rootBinding().compositeProperty()) .bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); assertSame(directCall, chainedCallWithCache); } @Test public void simpleCacheUsage() { Map<MapPropertyItemKey, MapPropertyItemValue> firstExpectedValue = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue() ); Map<MapPropertyItemKey, MapPropertyItemValue> secondExpectedValue = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue() ); rootValue.setMapProperty(firstExpectedValue); doReturn(rootValue).when(rootModel).getObject(); IBindableModel<RootValue> bindableModel = new BindableModel<>(rootModel); IBindableModel<Map<MapPropertyItemKey, MapPropertyItemValue>> propertyModel = bindableModel.bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); assertEquals(firstExpectedValue, propertyModel.getObject()); verify(rootValue).getMapProperty(); // Cache was initialized rootValue.setMapProperty(secondExpectedValue); propertyModel.readAll(); verify(rootValue, times(2)).getMapProperty(); // The value was fetched assertEquals(secondExpectedValue, propertyModel.getObject()); // The cache was updated verify(rootValue, times(2)).getMapProperty(); // Only the cache was touched, no the actual value Map<MapPropertyItemKey, MapPropertyItemValue> valueToSet = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue() ); assertEquals(secondExpectedValue, rootValue.getMapProperty()); propertyModel.setObject(valueToSet); assertEquals(secondExpectedValue, rootValue.getMapProperty()); // Only the cache was touched, not the actual value (which was only initialized at the start of this test) assertEquals(valueToSet, propertyModel.getObject()); propertyModel.writeAll(); assertEquals(valueToSet, rootValue.getMapProperty()); assertEquals(valueToSet, propertyModel.getObject()); } @Test public void cacheUpdatePropagation() { Map<MapPropertyItemKey, MapPropertyItemValue> firstExpectedValue = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue() ); Map<MapPropertyItemKey, MapPropertyItemValue> secondExpectedValue = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue() ); rootValue.setMapProperty(firstExpectedValue); doReturn(rootValue).when(rootModel).getObject(); IBindableModel<RootValue> bindableModel = new BindableModel<>(rootModel); IBindableModel<Map<MapPropertyItemKey, MapPropertyItemValue>> propertyModel = bindableModel.bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); assertEquals(firstExpectedValue, propertyModel.getObject()); verify(rootValue).getMapProperty(); // Cache was initialized rootValue.setMapProperty(secondExpectedValue); bindableModel.readAll(); verify(rootValue, times(2)).getMapProperty(); // The value was fetched assertEquals(secondExpectedValue, propertyModel.getObject()); // The cache was updated verify(rootValue, times(2)).getMapProperty(); // Only the cache was touched when calling getObject(), no the actual value Map<MapPropertyItemKey, MapPropertyItemValue> valueToSet = ImmutableMap.of( new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue(), new MapPropertyItemKey(), new MapPropertyItemValue() ); assertEquals(secondExpectedValue, rootValue.getMapProperty()); propertyModel.setObject(valueToSet); assertEquals(secondExpectedValue, rootValue.getMapProperty()); // Only the cache was touched, not the actual value (which was only initialized at the start of this test) assertEquals(valueToSet, propertyModel.getObject()); bindableModel.writeAll(); assertEquals(valueToSet, rootValue.getMapProperty()); assertEquals(valueToSet, propertyModel.getObject()); } @Test public void mapModelInterfaceUsage() { MapPropertyItemKey firstItemKey = new MapPropertyItemKey(); MapPropertyItemKey secondItemKey = new MapPropertyItemKey(); MapPropertyItemKey thirdItemKey = new MapPropertyItemKey(); MapPropertyItemValue firstItemValue = new MapPropertyItemValue(); MapPropertyItemValue secondItemValue = new MapPropertyItemValue(); MapPropertyItemValue thirdItemValue = new MapPropertyItemValue(); rootValue.setMapProperty(ImmutableMap.of(firstItemKey, firstItemValue, secondItemKey, secondItemValue)); doReturn(rootValue).when(rootModel).getObject(); IBindableModel<RootValue> bindableModel = new BindableModel<>(rootModel); IBindableMapModel<MapPropertyItemKey, MapPropertyItemValue, ?> propertyModel = bindableModel.bindMapWithCache( rootBinding().mapProperty(), Suppliers2.<MapPropertyItemKey, MapPropertyItemValue>linkedHashMap(), StubModel.<MapPropertyItemKey>factory(), StubModel.<MapPropertyItemValue>factory() ); assertEquals(propertyModel.getObject(), ImmutableMap.of(firstItemKey, firstItemValue, secondItemKey, secondItemValue)); // Cache was initialized propertyModel.remove(secondItemKey); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue), propertyModel.getObject()); // The cache was updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, secondItemKey, secondItemValue), rootValue.getMapProperty()); // The actual value was *not* updated propertyModel.writeAll(); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue), propertyModel.getObject()); // The cache was *not* updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue), rootValue.getMapProperty()); // The actual value was updated propertyModel.put(thirdItemKey, thirdItemValue); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, thirdItemValue), propertyModel.getObject()); // The cache was updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue), rootValue.getMapProperty()); // The actual value was *not* updated propertyModel.writeAll(); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, thirdItemValue), propertyModel.getObject()); // The cache was *not* updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, thirdItemValue), rootValue.getMapProperty()); // The actual value was updated propertyModel.put(thirdItemKey, secondItemValue); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, secondItemValue), propertyModel.getObject()); // The cache was updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, thirdItemValue), rootValue.getMapProperty()); // The actual value was *not* updated propertyModel.writeAll(); assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, secondItemValue), propertyModel.getObject()); // The cache was *not* updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, secondItemValue), rootValue.getMapProperty()); // The actual value was updated propertyModel.clear(); assertEquals(ImmutableMap.of(), propertyModel.getObject()); // The cache was updated assertEquals(ImmutableMap.of(firstItemKey, firstItemValue, thirdItemKey, secondItemValue), rootValue.getMapProperty()); // The actual value was *not* updated propertyModel.writeAll(); assertEquals(ImmutableMap.of(), propertyModel.getObject()); // The cache was *not* updated assertEquals(ImmutableMap.of(), rootValue.getMapProperty()); // The actual value was updated } }