1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.javafx.binding;
  27 
  28 import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
  29 import test.javafx.beans.InvalidationListenerMock;
  30 import javafx.beans.Observable;
  31 import javafx.beans.binding.MapBinding;
  32 import javafx.beans.property.ReadOnlyBooleanProperty;
  33 import javafx.beans.property.ReadOnlyIntegerProperty;
  34 import test.javafx.beans.value.ChangeListenerMock;
  35 import javafx.beans.value.ObservableValueBase;
  36 import javafx.collections.FXCollections;
  37 import test.javafx.collections.MockMapObserver;
  38 import javafx.collections.ObservableList;
  39 import javafx.collections.ObservableMap;
  40 import org.junit.Before;
  41 import org.junit.Test;
  42 
  43 import java.util.Collections;
  44 import java.util.HashMap;
  45 import java.util.Map;
  46 
  47 import static test.javafx.collections.MockMapObserver.Call;
  48 import static org.junit.Assert.*;
  49 
  50 /**
  51  */
  52 public class MapBindingTest {
  53 
  54     private final static Object KEY_1 = new Object();
  55     private final static Object KEY_2_0 = new Object();
  56     private final static Object KEY_2_1 = new Object();
  57     private final static Object DATA_1 = new Object();
  58     private final static Object DATA_2_0 = new Object();
  59     private final static Object DATA_2_1 = new Object();
  60 
  61     private ObservableStub dependency1;
  62     private ObservableStub dependency2;
  63 
  64     private MapBindingImpl binding0;
  65     private MapBindingImpl binding1;
  66     private MapBindingImpl binding2;
  67 
  68     private ObservableMap<Object, Object> emptyMap;
  69     private ObservableMap<Object, Object> set1;
  70     private ObservableMap<Object, Object> set2;
  71 
  72     private MockMapObserver<Object, Object> listener;
  73 
  74     @Before
  75     public void setUp() {
  76         dependency1 = new ObservableStub();
  77         dependency2 = new ObservableStub();
  78         binding0 = new MapBindingImpl();
  79         binding1 = new MapBindingImpl(dependency1);
  80         binding2 = new MapBindingImpl(dependency1, dependency2);
  81         emptyMap = FXCollections.observableMap(Collections.emptyMap());
  82         set1 = FXCollections.observableMap(Collections.singletonMap(KEY_1, DATA_1));
  83         final Map<Object, Object> map = new HashMap<Object, Object>();
  84         map.put(KEY_2_0, DATA_2_0);
  85         map.put(KEY_2_1, DATA_2_1);
  86         set2 = FXCollections.observableMap(map);
  87         listener = new MockMapObserver<Object, Object>();
  88         binding0.setValue(set2);
  89         binding1.setValue(set2);
  90         binding2.setValue(set2);
  91     }
  92 
  93     @Test
  94     public void testSizeProperty() {
  95         assertEquals(binding0, binding0.sizeProperty().getBean());
  96         assertEquals(binding1, binding1.sizeProperty().getBean());
  97         assertEquals(binding2, binding2.sizeProperty().getBean());
  98 
  99         final ReadOnlyIntegerProperty size = binding1.sizeProperty();
 100         assertEquals("size", size.getName());
 101 
 102         assertEquals(2, size.get());
 103         binding1.setValue(emptyMap);
 104         dependency1.fireValueChangedEvent();
 105         assertEquals(0, size.get());
 106         binding1.setValue(null);
 107         dependency1.fireValueChangedEvent();
 108         assertEquals(0, size.get());
 109         binding1.setValue(set1);
 110         dependency1.fireValueChangedEvent();
 111         assertEquals(1, size.get());
 112     }
 113 
 114     @Test
 115     public void testEmptyProperty() {
 116         assertEquals(binding0, binding0.emptyProperty().getBean());
 117         assertEquals(binding1, binding1.emptyProperty().getBean());
 118         assertEquals(binding2, binding2.emptyProperty().getBean());
 119 
 120         final ReadOnlyBooleanProperty empty = binding1.emptyProperty();
 121         assertEquals("empty", empty.getName());
 122 
 123         assertFalse(empty.get());
 124         binding1.setValue(emptyMap);
 125         dependency1.fireValueChangedEvent();
 126         assertTrue(empty.get());
 127         binding1.setValue(null);
 128         dependency1.fireValueChangedEvent();
 129         assertTrue(empty.get());
 130         binding1.setValue(set1);
 131         dependency1.fireValueChangedEvent();
 132         assertFalse(empty.get());
 133     }
 134 
 135     @Test
 136     public void testNoDependency_MapChangeListener() {
 137         binding0.getValue();
 138         binding0.addListener(listener);
 139         System.gc(); // making sure we did not not overdo weak references
 140         assertEquals(true, binding0.isValid());
 141 
 142         // calling getValue()
 143         binding0.reset();
 144         binding0.getValue();
 145         assertEquals(0, binding0.getComputeValueCounter());
 146         assertEquals(0, listener.getCallsNumber());
 147         assertEquals(true, binding0.isValid());
 148     }
 149 
 150     @Test
 151     public void testSingleDependency_MapChangeListener() {
 152         binding1.getValue();
 153         binding1.addListener(listener);
 154         System.gc(); // making sure we did not not overdo weak references
 155         assertEquals(true, binding1.isValid());
 156 
 157         // fire single change event
 158         binding1.reset();
 159         listener.clear();
 160         binding1.setValue(set1);
 161         dependency1.fireValueChangedEvent();
 162         assertEquals(1, binding1.getComputeValueCounter());
 163         listener.assertMultipleCalls(new Call[]{new Call<Object, Object>(KEY_2_0, DATA_2_0, null), new Call<Object, Object>(KEY_2_1, DATA_2_1, null), new Call<Object, Object>(KEY_1, null, DATA_1)});
 164         assertEquals(true, binding1.isValid());
 165         listener.clear();
 166 
 167         binding1.getValue();
 168         assertEquals(0, binding1.getComputeValueCounter());
 169         assertEquals(0, listener.getCallsNumber());
 170         assertEquals(true, binding1.isValid());
 171         listener.clear();
 172 
 173         // fire single change event with same value
 174         binding1.setValue(set1);
 175         dependency1.fireValueChangedEvent();
 176         assertEquals(1, binding1.getComputeValueCounter());
 177         assertEquals(0, listener.getCallsNumber());
 178         assertEquals(true, binding1.isValid());
 179         listener.clear();
 180 
 181         binding1.getValue();
 182         assertEquals(0, binding1.getComputeValueCounter());
 183         assertEquals(0, listener.getCallsNumber());
 184         assertEquals(true, binding1.isValid());
 185         listener.clear();
 186 
 187         // fire two change events
 188         binding1.setValue(set2);
 189         dependency1.fireValueChangedEvent();
 190         listener.clear();
 191         binding1.setValue(set1);
 192         dependency1.fireValueChangedEvent();
 193         assertEquals(2, binding1.getComputeValueCounter());
 194         listener.assertMultipleCalls(new Call[]{new Call<Object, Object>(KEY_2_0, DATA_2_0, null), new Call<Object, Object>(KEY_2_1, DATA_2_1, null), new Call<Object, Object>(KEY_1, null, DATA_1)});
 195         assertEquals(true, binding1.isValid());
 196         listener.clear();
 197 
 198         binding1.getValue();
 199         assertEquals(0, binding1.getComputeValueCounter());
 200         assertEquals(0, listener.getCallsNumber());
 201         assertEquals(true, binding1.isValid());
 202         listener.clear();
 203 
 204         // fire two change events with same value
 205         binding1.setValue(set2);
 206         dependency1.fireValueChangedEvent();
 207         binding1.setValue(set2);
 208         dependency1.fireValueChangedEvent();
 209         assertEquals(2, binding1.getComputeValueCounter());
 210         listener.assertMultipleCalls(new Call[] {new Call<Object, Object>(KEY_1, DATA_1, null), new Call<Object, Object>(KEY_2_0, null, DATA_2_0), new Call<Object, Object>(KEY_2_1, null, DATA_2_1)});
 211         assertEquals(true, binding1.isValid());
 212         listener.clear();
 213 
 214         binding1.getValue();
 215         assertEquals(0, binding1.getComputeValueCounter());
 216         assertEquals(0, listener.getCallsNumber());
 217         assertEquals(true, binding1.isValid());
 218     }
 219 
 220     @Test
 221     public void testChangeContent_InvalidationListener() {
 222         final InvalidationListenerMock listenerMock = new InvalidationListenerMock();
 223         binding1.get();
 224         binding1.addListener(listenerMock);
 225         assertTrue(binding1.isValid());
 226 
 227         binding1.reset();
 228         listenerMock.reset();
 229         set2.put(new Object(), new Object());
 230         assertEquals(0, binding1.getComputeValueCounter());
 231         listenerMock.check(binding1, 1);
 232         assertTrue(binding1.isValid());
 233     }
 234 
 235     @Test
 236     public void testChangeContent_ChangeListener() {
 237         final ChangeListenerMock listenerMock = new ChangeListenerMock(null);
 238         binding1.get();
 239         binding1.addListener(listenerMock);
 240         assertTrue(binding1.isValid());
 241 
 242         binding1.reset();
 243         listenerMock.reset();
 244         set2.put(new Object(), new Object());
 245         assertEquals(0, binding1.getComputeValueCounter());
 246         listenerMock.check(binding1, set2, set2, 1);
 247         assertTrue(binding1.isValid());
 248     }
 249 
 250     @Test
 251     public void testChangeContent_MapChangeListener() {
 252         binding1.get();
 253         binding1.addListener(listener);
 254         assertTrue(binding1.isValid());
 255 
 256         final Object newKey = new Object();
 257         final Object newData = new Object();
 258         binding1.reset();
 259         listener.clear();
 260         set2.put(newKey, newData);
 261         assertEquals(0, binding1.getComputeValueCounter());
 262         listener.assertAdded(MockMapObserver.Tuple.tup(newKey, newData));
 263         assertTrue(binding1.isValid());
 264     }
 265 
 266     public static class ObservableStub extends ObservableValueBase<Object> {
 267         @Override public void fireValueChangedEvent() {super.fireValueChangedEvent();}
 268 
 269         @Override
 270         public Object getValue() {
 271             return null;
 272         }
 273     }
 274 
 275     private static class MapBindingImpl extends MapBinding<Object, Object> {
 276 
 277         private int computeValueCounter = 0;
 278         private ObservableMap<Object, Object> value;
 279 
 280         public void setValue(ObservableMap<Object, Object> value) {
 281             this.value = value;
 282         }
 283 
 284         public MapBindingImpl(Observable... dep) {
 285             super.bind(dep);
 286         }
 287 
 288         public int getComputeValueCounter() {
 289             final int result = computeValueCounter;
 290             reset();
 291             return result;
 292         }
 293 
 294         public void reset() {
 295             computeValueCounter = 0;
 296         }
 297 
 298         @Override
 299         public ObservableMap<Object, Object> computeValue() {
 300             computeValueCounter++;
 301             return value;
 302         }
 303 
 304         @Override @ReturnsUnmodifiableCollection
 305         public ObservableList<?> getDependencies() {
 306             fail("Should not reach here");
 307             return null;
 308         }
 309     }
 310 
 311 
 312 //    private class MapChangeListenerMock implements MapChangeListener<Object, Object> {
 313 //        
 314 //        private Change<? extends Object> change;
 315 //        private int counter;
 316 //
 317 //        @Override
 318 //        public void onChanged(Change<? extends Object> change) {
 319 //            this.change = change;
 320 //            counter++;
 321 //        }
 322 //        
 323 //        private void reset() {
 324 //            change = null;
 325 //            counter = 0;
 326 //        }
 327 //
 328 //        private void checkNotCalled() {
 329 //            assertEquals(null, change);
 330 //            assertEquals(0, counter);
 331 //            reset();
 332 //        }
 333 //
 334 //        private void check(ObservableMap<Object, Object> oldMap, ObservableMap<Object, Object> newMap, int counter) {
 335 //            assertTrue(change.next());
 336 //            assertTrue(change.wasReplaced());
 337 //            assertEquals(oldMap, change.getRemoved());
 338 //            assertEquals(newMap, change.getMap());
 339 //            assertFalse(change.next());
 340 //            assertEquals(counter, this.counter);
 341 //            reset();
 342 //        }
 343 //
 344 //        private void check(int pos, Object newObject, int counter) {
 345 //            assertTrue(change.next());
 346 //            assertTrue(change.wasAdded());
 347 //            assertEquals(pos, change.getFrom());
 348 //            assertEquals(Collections.singletonMap(newObject), change.getAddedSubMap());
 349 //            assertFalse(change.next());
 350 //            assertEquals(counter, this.counter);
 351 //            reset();
 352 //        }
 353 //    }
 354 }