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 com.sun.javafx.binding;
27
28 import javafx.beans.InvalidationListener;
29 import javafx.beans.binding.Bindings;
30 import javafx.beans.property.*;
31 import javafx.beans.value.ChangeListener;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.junit.runners.Parameterized;
36
37 import java.util.Arrays;
38 import java.util.Collection;
39
40 import static org.junit.Assert.*;
41 import org.junit.Rule;
42 import org.junit.rules.ExpectedException;
43
44 @RunWith(Parameterized.class)
45 public class BidirectionalBindingTest<T> {
46
47 private static final float EPSILON_FLOAT = 1e-5f;
48 private static final double EPSILON_DOUBLE = 1e-10;
49
50 public static interface Functions<S> {
51 PropertyMock<S> create();
52 void bind(PropertyMock<S> obj1, PropertyMock<S> obj2);
53 void unbind(PropertyMock<S> obj1, PropertyMock<S> obj2);
54 BidirectionalBinding createBindingDirectly(PropertyMock<S> op1, PropertyMock<S> op2);
55 void check(S expected, S actual);
56 }
57
58 private final Functions<T> func;
59 private final T[] v;
60
61 @Rule
62 public ExpectedException thrown = ExpectedException.none();
63
64 private PropertyMock<T> op1;
65 private PropertyMock<T> op2;
66 private PropertyMock<T> op3;
67 private PropertyMock<T> op4;
68
69 public BidirectionalBindingTest(Functions<T> func, T[] v) {
70 this.op1 = func.create();
71 this.op2 = func.create();
72 this.op3 = func.create();
73 this.op4 = func.create();
74 this.func = func;
75 this.v = v;
76 }
77
78 @Before
79 public void setUp() {
80 op1.setValue(v[0]);
81 op2.setValue(v[1]);
82 }
83
84 @Test
85 public void testBind() {
86 func.bind(op1, op2);
87 System.gc(); // making sure we did not not overdo weak references
88 func.check(v[1], op1.getValue());
89 func.check(v[1], op2.getValue());
90
91 op1.setValue(v[2]);
92 func.check(v[2], op1.getValue());
93 func.check(v[2], op2.getValue());
94
95 op2.setValue(v[3]);
96 func.check(v[3], op1.getValue());
97 func.check(v[3], op2.getValue());
98 }
99
100 @Test
101 public void testUnbind() {
102 // unbind non-existing binding => no-op
103 func.unbind(op1, op2);
104
105 // unbind properties of different beans
106 func.bind(op1, op2);
107 System.gc(); // making sure we did not not overdo weak references
108 func.check(v[1], op1.getValue());
109 func.check(v[1], op2.getValue());
110
111 func.unbind(op1, op2);
112 System.gc();
113 func.check(v[1], op1.getValue());
114 func.check(v[1], op2.getValue());
115
116 op1.setValue(v[2]);
117 func.check(v[2], op1.getValue());
118 func.check(v[1], op2.getValue());
119
120 op2.setValue(v[3]);
121 func.check(v[2], op1.getValue());
122 func.check(v[3], op2.getValue());
123 }
124
125 @Test
126 public void testChaining() {
127 op3.setValue(v[2]);
128 func.bind(op1, op2);
129 func.bind(op2, op3);
130 System.gc(); // making sure we did not not overdo weak references
131 func.check(v[2], op1.getValue());
132 func.check(v[2], op2.getValue());
133 func.check(v[2], op3.getValue());
134
135 op1.setValue(v[3]);
136 func.check(v[3], op1.getValue());
137 func.check(v[3], op2.getValue());
138 func.check(v[3], op3.getValue());
139
140 op2.setValue(v[0]);
141 func.check(v[0], op1.getValue());
142 func.check(v[0], op2.getValue());
143 func.check(v[0], op3.getValue());
144
145 op3.setValue(v[1]);
146 func.check(v[1], op1.getValue());
147 func.check(v[1], op2.getValue());
148 func.check(v[1], op3.getValue());
149
150 // now unbind
151 func.unbind(op1, op2);
152 System.gc(); // making sure we did not not overdo weak references
153 func.check(v[1], op1.getValue());
154 func.check(v[1], op2.getValue());
155 func.check(v[1], op3.getValue());
156
157 op1.setValue(v[2]);
158 func.check(v[2], op1.getValue());
159 func.check(v[1], op2.getValue());
160 func.check(v[1], op3.getValue());
161
162 op2.setValue(v[3]);
163 func.check(v[2], op1.getValue());
164 func.check(v[3], op2.getValue());
165 func.check(v[3], op3.getValue());
166
167 op3.setValue(v[0]);
168 func.check(v[2], op1.getValue());
169 func.check(v[0], op2.getValue());
170 func.check(v[0], op3.getValue());
171 }
172
173 @Test
174 public void testWeakReferencing() {
175 func.bind(op1, op2);
176 assertEquals(1, op1.getListenerCount());
177 assertEquals(1, op2.getListenerCount());
178
179 op1 = null;
180 System.gc();
181 op2.setValue(v[2]);
182 assertEquals(0, op2.getListenerCount());
183
184 func.bind(op2, op3);
185 assertEquals(1, op2.getListenerCount());
186 assertEquals(1, op3.getListenerCount());
187
188 op3 = null;
189 System.gc();
190 op2.setValue(v[0]);
191 assertEquals(0, op2.getListenerCount());
192 }
193
194 @Test
195 public void testHashCode() {
196 final int hc1 = func.createBindingDirectly(op1, op2).hashCode();
197 final int hc2 = func.createBindingDirectly(op2, op1).hashCode();
198 assertEquals(hc1, hc2);
199 }
200
201
202 @Test
203 public void testEquals() {
204 final BidirectionalBinding golden = func.createBindingDirectly(op1, op2);
205
206 assertTrue(golden.equals(golden));
207 assertFalse(golden.equals(null));
208 assertFalse(golden.equals(op1));
209 assertTrue(golden.equals(func.createBindingDirectly(op1, op2)));
210 assertTrue(golden.equals(func.createBindingDirectly(op2, op1)));
211 assertFalse(golden.equals(func.createBindingDirectly(op1, op3)));
212 assertFalse(golden.equals(func.createBindingDirectly(op3, op1)));
213 assertFalse(golden.equals(func.createBindingDirectly(op3, op2)));
214 assertFalse(golden.equals(func.createBindingDirectly(op2, op3)));
215 }
216
217 @Test
218 public void testEqualsWithGCedProperty() {
219 final BidirectionalBinding binding1 = func.createBindingDirectly(op1, op2);
220 final BidirectionalBinding binding2 = func.createBindingDirectly(op1, op2);
221 final BidirectionalBinding binding3 = func.createBindingDirectly(op2, op1);
222 final BidirectionalBinding binding4 = func.createBindingDirectly(op2, op1);
223 op1 = null;
224 System.gc();
225
226 assertTrue(binding1.equals(binding1));
227 assertFalse(binding1.equals(binding2));
228 assertFalse(binding1.equals(binding3));
229
230 assertTrue(binding3.equals(binding3));
231 assertFalse(binding3.equals(binding1));
232 assertFalse(binding3.equals(binding4));
233 }
234
235 @Test(expected=NullPointerException.class)
236 public void testBind_Null_X() {
237 func.bind(null, op2);
238 }
239
240 @Test(expected=NullPointerException.class)
241 public void testBind_X_Null() {
242 func.bind(op1, null);
243 }
244
245 @Test(expected=IllegalArgumentException.class)
246 public void testBind_X_Self() {
247 func.bind(op1, op1);
248 }
249
250 @Test(expected=NullPointerException.class)
251 public void testUnbind_Null_X() {
252 func.unbind(null, op2);
253 }
254
255 @Test(expected=NullPointerException.class)
256 public void testUnbind_X_Null() {
257 func.unbind(op1, null);
258 }
259
260 @Test(expected=IllegalArgumentException.class)
261 public void testUnbind_X_Self() {
262 func.unbind(op1, op1);
263 }
264
265 @Test
266 public void testBrokenBind() {
267 func.bind(op1, op2);
268 op1.bind(op3);
269 assertEquals(op3.getValue(), op1.getValue());
270 assertEquals(op2.getValue(), op1.getValue());
271
272 op2.setValue(v[2]);
273 assertEquals(op3.getValue(), op1.getValue());
274 assertEquals(op2.getValue(), op1.getValue());
275 }
276
277 @Test
278 public void testDoubleBrokenBind() {
279 func.bind(op1, op2);
280 op1.bind(op3);
281 op4.setValue(v[0]);
282
283 op2.bind(op4);
284 assertEquals(op4.getValue(), op2.getValue());
285 assertEquals(op3.getValue(), op1.getValue());
286 // Test that bidirectional binding was unbound in this case
287 op3.setValue(v[0]);
288 op4.setValue(v[1]);
289 assertEquals(op4.getValue(), op2.getValue());
290 assertEquals(op3.getValue(), op1.getValue());
291 assertEquals(v[0], op1.getValue());
292 assertEquals(v[1], op2.getValue());
293 }
294
295 @Parameterized.Parameters
296 public static Collection<Object[]> parameters() {
297 final Boolean[] booleanData = new Boolean[] {true, false, true, false};
298 final Double[] doubleData = new Double[] {2348.2345, -92.214, -214.0214, -908.214};
299 final Float[] floatData = new Float[] {-3592.9f, 234872.8347f, 3897.274f, 3958.938745f};
300 final Integer[] integerData = new Integer[] {248, -9384, -234, -34};
301 final Long[] longData = new Long[] {9823984L, 2908934L, -234234L, 9089234L};
302 final Object[] objectData = new Object[] {new Object(), new Object(), new Object(), new Object()};
303 final String[] stringData = new String[] {"A", "B", "C", "D"};
304
305 return Arrays.asList(new Object[][] {
306 // boolean
307 {
308 new Functions<Boolean>() {
309 @Override
310 public PropertyMock<Boolean> create() {
311 return new BooleanPropertyMock();
312 }
313 @Override
314 public void bind(PropertyMock<Boolean> op1, PropertyMock<Boolean> op2) {
315 Bindings.bindBidirectional(op1, op2);
316 }
317 @Override
318 public void unbind(PropertyMock<Boolean> op1, PropertyMock<Boolean> op2) {
319 Bindings.unbindBidirectional(op1, op2);
320 }
321 @Override
322 public BidirectionalBinding createBindingDirectly(PropertyMock<Boolean> op1, PropertyMock<Boolean> op2) {
323 return BidirectionalBinding.bind(op1, op2);
324 }
325 @Override
326 public void check(Boolean expected, Boolean actual) {
327 assertEquals(expected, actual);
328 }
329 },
330 booleanData
331 },
332 // double
333 {
334 new Functions<Number>() {
335 @Override
336 public PropertyMock<Number> create() {
337 return new DoublePropertyMock();
338 }
339 @Override
340 public void bind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
341 Bindings.bindBidirectional(op1, op2);
342 }
343 @Override
344 public void unbind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
345 Bindings.unbindBidirectional(op1, op2);
346 }
347 @Override
348 public BidirectionalBinding createBindingDirectly(PropertyMock<Number> op1, PropertyMock<Number> op2) {
349 return BidirectionalBinding.bind(op1, op2);
350 }
351 @Override
352 public void check(Number expected, Number actual) {
353 assertEquals(expected.doubleValue(), actual.doubleValue(), EPSILON_DOUBLE);
354 }
355 },
356 doubleData
357 },
358 // float
359 {
360 new Functions<Number>() {
361 @Override
362 public PropertyMock<Number> create() {
363 return new FloatPropertyMock();
364 }
365 @Override
366 public void bind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
367 Bindings.bindBidirectional(op1, op2);
368 }
369 @Override
370 public void unbind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
371 Bindings.unbindBidirectional(op1, op2);
372 }
373 @Override
374 public BidirectionalBinding createBindingDirectly(PropertyMock<Number> op1, PropertyMock<Number> op2) {
375 return BidirectionalBinding.bind(op1, op2);
376 }
377 @Override
378 public void check(Number expected, Number actual) {
379 assertEquals(expected.floatValue(), actual.floatValue(), EPSILON_FLOAT);
380 }
381 },
382 floatData
383 },
384 // integer
385 {
386 new Functions<Number>() {
387 @Override
388 public PropertyMock<Number> create() {
389 return new IntegerPropertyMock();
390 }
391 @Override
392 public void bind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
393 Bindings.bindBidirectional(op1, op2);
394 }
395 @Override
396 public void unbind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
397 Bindings.unbindBidirectional(op1, op2);
398 }
399 @Override
400 public BidirectionalBinding createBindingDirectly(PropertyMock<Number> op1, PropertyMock<Number> op2) {
401 return BidirectionalBinding.bind(op1, op2);
402 }
403 @Override
404 public void check(Number expected, Number actual) {
405 assertEquals(expected.intValue(), actual.intValue());
406 }
407 },
408 integerData
409 },
410 // long
411 {
412 new Functions<Number>() {
413 @Override
414 public PropertyMock<Number> create() {
415 return new LongPropertyMock();
416 }
417 @Override
418 public void bind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
419 Bindings.bindBidirectional(op1, op2);
420 }
421 @Override
422 public void unbind(PropertyMock<Number> op1, PropertyMock<Number> op2) {
423 Bindings.unbindBidirectional(op1, op2);
424 }
425 @Override
426 public BidirectionalBinding createBindingDirectly(PropertyMock<Number> op1, PropertyMock<Number> op2) {
427 return BidirectionalBinding.bind(op1, op2);
428 }
429 @Override
430 public void check(Number expected, Number actual) {
431 assertEquals(expected.longValue(), actual.longValue());
432 }
433 },
434 longData
435 },
436 // object
437 {
438 new Functions<Object>() {
439 @Override
440 public PropertyMock<Object> create() {
441 return new ObjectPropertyMock<Object>();
442 }
443 @Override
444 public void bind(PropertyMock<Object> op1, PropertyMock<Object> op2) {
445 Bindings.bindBidirectional(op1, op2);
446 }
447 @Override
448 public void unbind(PropertyMock<Object> op1, PropertyMock<Object> op2) {
449 Bindings.unbindBidirectional(op1, op2);
450 }
451 @Override
452 public BidirectionalBinding createBindingDirectly(PropertyMock<Object> op1, PropertyMock<Object> op2) {
453 return BidirectionalBinding.bind(op1, op2);
454 }
455 @Override
456 public void check(Object expected, Object actual) {
457 assertEquals(expected, actual);
458 }
459 },
460 objectData
461 },
462 // string
463 {
464 new Functions<String>() {
465 @Override
466 public PropertyMock<String> create() {
467 return new StringPropertyMock();
468 }
469 @Override
470 public void bind(PropertyMock<String> op1, PropertyMock<String> op2) {
471 Bindings.bindBidirectional(op1, op2);
472 }
473 @Override
474 public void unbind(PropertyMock<String> op1, PropertyMock<String> op2) {
475 Bindings.unbindBidirectional(op1, op2);
476 }
477 @Override
478 public BidirectionalBinding createBindingDirectly(PropertyMock<String> op1, PropertyMock<String> op2) {
479 return BidirectionalBinding.bind(op1, op2);
480 }
481 @Override
482 public void check(String expected, String actual) {
483 assertEquals(expected, actual);
484 }
485 },
486 stringData
487 },
488 });
489 }
490
491 private interface PropertyMock<T> extends Property<T> {
492 int getListenerCount();
493 }
494
495 private static class BooleanPropertyMock extends SimpleBooleanProperty implements PropertyMock<Boolean> {
496
497 private int listenerCount = 0;
498
499 @Override
500 public int getListenerCount() {
501 return listenerCount;
502 }
503
504 @Override
505 public void addListener(ChangeListener<? super Boolean> listener) {
506 super.addListener(listener);
507 listenerCount++;
508 }
509
510 @Override
511 public void removeListener(ChangeListener<? super Boolean> listener) {
512 super.removeListener(listener);
513 listenerCount--;
514 }
515 }
516
517 private static class DoublePropertyMock extends SimpleDoubleProperty implements PropertyMock<Number> {
518
519 private int listenerCount = 0;
520
521 @Override
522 public int getListenerCount() {
523 return listenerCount;
524 }
525
526 @Override
527 public void addListener(ChangeListener<? super Number> listener) {
528 super.addListener(listener);
529 listenerCount++;
530 }
531
532 @Override
533 public void removeListener(ChangeListener<? super Number> listener) {
534 super.removeListener(listener);
535 listenerCount--;
536 }
537 }
538
539 private static class FloatPropertyMock extends SimpleFloatProperty implements PropertyMock<Number> {
540
541 private int listenerCount = 0;
542
543 @Override
544 public int getListenerCount() {
545 return listenerCount;
546 }
547
548 @Override
549 public void addListener(ChangeListener<? super Number> listener) {
550 super.addListener(listener);
551 listenerCount++;
552 }
553
554 @Override
555 public void removeListener(ChangeListener<? super Number> listener) {
556 super.removeListener(listener);
557 listenerCount--;
558 }
559 }
560
561 private static class IntegerPropertyMock extends SimpleIntegerProperty implements PropertyMock<Number> {
562
563 private int listenerCount = 0;
564
565 @Override
566 public int getListenerCount() {
567 return listenerCount;
568 }
569
570 @Override
571 public void addListener(ChangeListener<? super Number> listener) {
572 super.addListener(listener);
573 listenerCount++;
574 }
575
576 @Override
577 public void removeListener(ChangeListener<? super Number> listener) {
578 super.removeListener(listener);
579 listenerCount--;
580 }
581 }
582
583 private static class LongPropertyMock extends SimpleLongProperty implements PropertyMock<Number> {
584
585 private int listenerCount = 0;
586
587 @Override
588 public int getListenerCount() {
589 return listenerCount;
590 }
591
592 @Override
593 public void addListener(ChangeListener<? super Number> listener) {
594 super.addListener(listener);
595 listenerCount++;
596 }
597
598 @Override
599 public void removeListener(ChangeListener<? super Number> listener) {
600 super.removeListener(listener);
601 listenerCount--;
602 }
603 }
604
605 private static class ObjectPropertyMock<T> extends SimpleObjectProperty<T> implements PropertyMock<T> {
606
607 private int listenerCount = 0;
608
609 @Override
610 public int getListenerCount() {
611 return listenerCount;
612 }
613
614 @Override
615 public void addListener(ChangeListener<? super T> listener) {
616 super.addListener(listener);
617 listenerCount++;
618 }
619
620 @Override
621 public void removeListener(ChangeListener<? super T> listener) {
622 super.removeListener(listener);
623 listenerCount--;
624 }
625 }
626
627 private static class StringPropertyMock extends SimpleStringProperty implements PropertyMock<String> {
628
629 private int listenerCount = 0;
630
631 @Override
632 public int getListenerCount() {
633 return listenerCount;
634 }
635
636 @Override
637 public void addListener(ChangeListener<? super String> listener) {
638 super.addListener(listener);
639 listenerCount++;
640 }
641
642 @Override
643 public void removeListener(ChangeListener<? super String> listener) {
644 super.removeListener(listener);
645 listenerCount--;
646 }
647 }
648 }
|
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 com.sun.javafx.binding;
27
28 import javafx.beans.binding.Bindings;
29 import javafx.beans.property.*;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 import org.junit.runners.Parameterized;
34
35 import java.util.Arrays;
36 import java.util.Collection;
37 import javafx.beans.value.ObservableValue;
38
39 import static org.junit.Assert.*;
40
41 @RunWith(Parameterized.class)
42 public class BidirectionalBindingTest<T> {
43
44 @FunctionalInterface
45 public static interface PropertyFactory<T> {
46 Property<T> createProperty();
47 }
48
49 public static class Factory<T> {
50
51 private PropertyFactory<T> propertyFactory;
52 private T[] values;
53 public Factory(PropertyFactory<T> propertyFactory, T[] values) {
54 this.propertyFactory = propertyFactory;
55 this.values = values;
56 }
57 public Property<T> createProperty() {
58 return propertyFactory.createProperty();
59 }
60 public T[] getValues() {
61 return values;
62 }
63 }
64
65 private Factory<T> factory;
66 private Property<T> op1;
67 private Property<T> op2;
68 private Property<T> op3;
69 private Property<T> op4;
70 private T[] v;
71
72 public BidirectionalBindingTest(Factory<T> factory) {
73 this.factory = factory;
74 }
75
76 @Before
77 public void setUp() {
78 op1 = factory.createProperty();
79 op2 = factory.createProperty();
80 op3 = factory.createProperty();
81 op4 = factory.createProperty();
82 v = factory.getValues();
83 op1.setValue(v[0]);
84 op2.setValue(v[1]);
85 }
86
87 @Test
88 public void testBind() {
89 Bindings.bindBidirectional(op1, op2);
90 Bindings.bindBidirectional(op1, op2);
91 System.gc(); // making sure we did not not overdo weak references
92 assertEquals(v[1], op1.getValue());
93 assertEquals(v[1], op2.getValue());
94
95 op1.setValue(v[2]);
96 assertEquals(v[2], op1.getValue());
97 assertEquals(v[2], op2.getValue());
98
99 op2.setValue(v[3]);
100 assertEquals(v[3], op1.getValue());
101 assertEquals(v[3], op2.getValue());
102 }
103
104 @Test
105 public void testUnbind() {
106 // unbind non-existing binding => no-op
107 Bindings.unbindBidirectional(op1, op2);
108
109 // unbind properties of different beans
110 Bindings.bindBidirectional(op1, op2);
111 System.gc(); // making sure we did not not overdo weak references
112 assertEquals(v[1], op1.getValue());
113 assertEquals(v[1], op2.getValue());
114
115 Bindings.unbindBidirectional(op1, op2);
116 System.gc();
117 assertEquals(v[1], op1.getValue());
118 assertEquals(v[1], op2.getValue());
119
120 op1.setValue(v[2]);
121 assertEquals(v[2], op1.getValue());
122 assertEquals(v[1], op2.getValue());
123
124 op2.setValue(v[3]);
125 assertEquals(v[2], op1.getValue());
126 assertEquals(v[3], op2.getValue());
127 }
128
129 @Test
130 public void testChaining() {
131 op3.setValue(v[2]);
132 Bindings.bindBidirectional(op1, op2);
133 Bindings.bindBidirectional(op2, op3);
134 System.gc(); // making sure we did not not overdo weak references
135 assertEquals(v[2], op1.getValue());
136 assertEquals(v[2], op2.getValue());
137 assertEquals(v[2], op3.getValue());
138
139 op1.setValue(v[3]);
140 assertEquals(v[3], op1.getValue());
141 assertEquals(v[3], op2.getValue());
142 assertEquals(v[3], op3.getValue());
143
144 op2.setValue(v[0]);
145 assertEquals(v[0], op1.getValue());
146 assertEquals(v[0], op2.getValue());
147 assertEquals(v[0], op3.getValue());
148
149 op3.setValue(v[1]);
150 assertEquals(v[1], op1.getValue());
151 assertEquals(v[1], op2.getValue());
152 assertEquals(v[1], op3.getValue());
153
154 // now unbind
155 Bindings.unbindBidirectional(op1, op2);
156 System.gc(); // making sure we did not not overdo weak references
157 assertEquals(v[1], op1.getValue());
158 assertEquals(v[1], op2.getValue());
159 assertEquals(v[1], op3.getValue());
160
161 op1.setValue(v[2]);
162 assertEquals(v[2], op1.getValue());
163 assertEquals(v[1], op2.getValue());
164 assertEquals(v[1], op3.getValue());
165
166 op2.setValue(v[3]);
167 assertEquals(v[2], op1.getValue());
168 assertEquals(v[3], op2.getValue());
169 assertEquals(v[3], op3.getValue());
170
171 op3.setValue(v[0]);
172 assertEquals(v[2], op1.getValue());
173 assertEquals(v[0], op2.getValue());
174 assertEquals(v[0], op3.getValue());
175 }
176
177 private int getListenerCount(ObservableValue<T> v) {
178 return ExpressionHelperUtility.getChangeListeners(v).size();
179 }
180
181 @Test
182 public void testWeakReferencing() {
183 Bindings.bindBidirectional(op1, op2);
184
185 assertEquals(1, getListenerCount(op1));
186 assertEquals(1, getListenerCount(op2));
187
188 op1 = null;
189 System.gc();
190 op2.setValue(v[2]);
191 assertEquals(0, getListenerCount(op2));
192
193 Bindings.bindBidirectional(op2, op3);
194 assertEquals(1, getListenerCount(op2));
195 assertEquals(1, getListenerCount(op3));
196
197 op3 = null;
198 System.gc();
199 op2.setValue(v[0]);
200 assertEquals(0, getListenerCount(op2));
201 }
202
203 @Test
204 public void testHashCode() {
205 final int hc1 = BidirectionalBinding.bind(op1, op2).hashCode();
206 final int hc2 = BidirectionalBinding.bind(op2, op1).hashCode();
207 assertEquals(hc1, hc2);
208 }
209
210 @Test
211 public void testEquals() {
212 final BidirectionalBinding golden = BidirectionalBinding.bind(op1, op2);
213
214 assertTrue(golden.equals(golden));
215 assertFalse(golden.equals(null));
216 assertFalse(golden.equals(op1));
217 assertTrue(golden.equals(BidirectionalBinding.bind(op1, op2)));
218 assertTrue(golden.equals(BidirectionalBinding.bind(op2, op1)));
219 assertFalse(golden.equals(BidirectionalBinding.bind(op1, op3)));
220 assertFalse(golden.equals(BidirectionalBinding.bind(op3, op1)));
221 assertFalse(golden.equals(BidirectionalBinding.bind(op3, op2)));
222 assertFalse(golden.equals(BidirectionalBinding.bind(op2, op3)));
223 }
224
225 @Test
226 public void testEqualsWithGCedProperty() {
227 final BidirectionalBinding binding1 = BidirectionalBinding.bind(op1, op2);
228 final BidirectionalBinding binding2 = BidirectionalBinding.bind(op1, op2);
229 final BidirectionalBinding binding3 = BidirectionalBinding.bind(op2, op1);
230 final BidirectionalBinding binding4 = BidirectionalBinding.bind(op2, op1);
231 op1 = null;
232 System.gc();
233
234 assertTrue(binding1.equals(binding1));
235 assertFalse(binding1.equals(binding2));
236 assertFalse(binding1.equals(binding3));
237
238 assertTrue(binding3.equals(binding3));
239 assertFalse(binding3.equals(binding1));
240 assertFalse(binding3.equals(binding4));
241 }
242
243 @Test(expected=NullPointerException.class)
244 public void testBind_Null_X() {
245 Bindings.bindBidirectional(null, op2);
246 }
247
248 @Test(expected=NullPointerException.class)
249 public void testBind_X_Null() {
250 Bindings.bindBidirectional(op1, null);
251 }
252
253 @Test(expected=IllegalArgumentException.class)
254 public void testBind_X_Self() {
255 Bindings.bindBidirectional(op1, op1);
256 }
257
258 @Test(expected=NullPointerException.class)
259 public void testUnbind_Null_X() {
260 Bindings.unbindBidirectional(null, op2);
261 }
262
263 @Test(expected=NullPointerException.class)
264 public void testUnbind_X_Null() {
265 Bindings.unbindBidirectional(op1, null);
266 }
267
268 @Test(expected=IllegalArgumentException.class)
269 public void testUnbind_X_Self() {
270 Bindings.unbindBidirectional(op1, op1);
271 }
272
273 @Test
274 public void testBrokenBind() {
275 Bindings.bindBidirectional(op1, op2);
276 op1.bind(op3);
277 assertEquals(op3.getValue(), op1.getValue());
278 assertEquals(op2.getValue(), op1.getValue());
279
280 op2.setValue(v[2]);
281 assertEquals(op3.getValue(), op1.getValue());
282 assertEquals(op2.getValue(), op1.getValue());
283 }
284
285 @Test
286 public void testDoubleBrokenBind() {
287 Bindings.bindBidirectional(op1, op2);
288 op1.bind(op3);
289 op4.setValue(v[0]);
290
291 op2.bind(op4);
292 assertEquals(op4.getValue(), op2.getValue());
293 assertEquals(op3.getValue(), op1.getValue());
294 // Test that bidirectional binding was unbound in this case
295 op3.setValue(v[0]);
296 op4.setValue(v[1]);
297 assertEquals(op4.getValue(), op2.getValue());
298 assertEquals(op3.getValue(), op1.getValue());
299 assertEquals(v[0], op1.getValue());
300 assertEquals(v[1], op2.getValue());
301 }
302
303 @Parameterized.Parameters
304 public static Collection<Object[]> parameters() {
305 final Boolean[] booleanData = new Boolean[] {true, false, true, false};
306 final Double[] doubleData = new Double[] {2348.2345, -92.214, -214.0214, -908.214};
307 final Float[] floatData = new Float[] {-3592.9f, 234872.8347f, 3897.274f, 3958.938745f};
308 final Integer[] integerData = new Integer[] {248, -9384, -234, -34};
309 final Long[] longData = new Long[] {9823984L, 2908934L, -234234L, 9089234L};
310 final Object[] objectData = new Object[] {new Object(), new Object(), new Object(), new Object()};
311 final String[] stringData = new String[] {"A", "B", "C", "D"};
312
313 return Arrays.asList(new Object[][] {
314 { new Factory(() -> new SimpleBooleanProperty(), booleanData) },
315 { new Factory(() -> new SimpleDoubleProperty(), doubleData) },
316 { new Factory(() -> new SimpleFloatProperty(), floatData) },
317 { new Factory(() -> new SimpleIntegerProperty(), integerData) },
318 { new Factory(() -> new SimpleLongProperty(), longData) },
319 { new Factory(() -> new SimpleObjectProperty<>(), objectData) },
320 { new Factory(() -> new SimpleStringProperty(), stringData) },
321 { new Factory(() -> new ReadOnlyBooleanWrapper(), booleanData) },
322 { new Factory(() -> new ReadOnlyDoubleWrapper(), doubleData) },
323 { new Factory(() -> new ReadOnlyFloatWrapper(), floatData) },
324 { new Factory(() -> new ReadOnlyIntegerWrapper(), integerData) },
325 { new Factory(() -> new ReadOnlyLongWrapper(), longData) },
326 { new Factory(() -> new ReadOnlyObjectWrapper<>(), objectData) },
327 { new Factory(() -> new ReadOnlyStringWrapper(), stringData) },
328 });
329 }
330 }
|