@qooxdoo/framework
Version:
The JS Framework for Coders
862 lines (711 loc) • 21.8 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2007-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Martin Wittemann (martinwittemann)
************************************************************************ */
/**
* Test-Class for testing the single value binding
*
* @ignore(qx.test.MultiBinding)
*/
qx.Class.define("qx.test.data.singlevalue.Deep", {
extend: qx.dev.unit.TestCase,
include: [qx.dev.unit.MMock],
construct() {
super();
// define a test class
qx.Class.define("qx.test.MultiBinding", {
extend: qx.core.Object,
properties: {
child: {
check: "qx.test.MultiBinding",
event: "changeChild",
nullable: true
},
childWithout: {
check: "qx.test.MultiBinding",
nullable: true
},
name: {
check: "String",
nullable: true,
init: "Juhu",
event: "changeName"
},
array: {
init: null,
event: "changeArray"
},
lab: {
event: "changeLable"
}
},
destruct() {
if (this.getLab()) {
this.getLab().dispose();
}
if (this.getArray()) {
this.getArray().dispose();
}
}
});
},
members: {
__a: null,
__b1: null,
__b2: null,
__label: null,
setUp() {
this.__a = new qx.test.MultiBinding().set({
name: "a",
lab: new qx.test.data.singlevalue.TextFieldDummy(""),
array: new qx.data.Array(["one", "two", "three"])
});
this.__b1 = new qx.test.MultiBinding().set({
name: "b1",
lab: new qx.test.data.singlevalue.TextFieldDummy(""),
array: new qx.data.Array(["one", "two", "three"])
});
this.__b2 = new qx.test.MultiBinding().set({
name: "b2",
lab: new qx.test.data.singlevalue.TextFieldDummy(""),
array: new qx.data.Array(["one", "two", "three"])
});
this.__label = new qx.test.data.singlevalue.TextFieldDummy();
},
tearDown() {
this.__b1.dispose();
this.__b2.dispose();
this.__a.dispose();
this.__label.dispose();
},
testConverterChainBroken() {
var m = qx.data.marshal.Json.createModel({ a: { a: 1 }, b: 2 });
var called = 0;
m.bind("a.a", m, "b", {
converter(data) {
called++;
return 3;
}
});
// check the init values
this.assertEquals(1, called);
this.assertEquals(3, m.getB());
// set the binding leaf to null
m.getA().setA(null);
this.assertEquals(2, called);
this.assertEquals(3, m.getB());
// set the binding root to null
m.setA(null);
this.assertEquals(3, called);
this.assertEquals(3, m.getB());
m.dispose();
},
testConverterChainBrokenInitialNull() {
var m = qx.data.marshal.Json.createModel({ a: null });
var t = qx.data.marshal.Json.createModel({ a: null });
var spy = this.spy(function () {
return 123;
});
m.bind("a.b", t, "a", { converter: spy });
this.assertCalledOnce(spy);
this.assertCalledWith(spy, undefined, undefined, m, t);
this.assertEquals(123, t.getA());
m.dispose();
t.dispose();
},
testDepthOf2() {
// create a hierarchy
// a --> b1
this.__a.setChild(this.__b1);
// create the binding
// a --> b1 --> label
qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
// just set the name of the second component
this.__b1.setName("B1");
this.assertEquals(
"B1",
this.__label.getValue(),
"Deep binding does not work with updating the first parameter."
);
// change the second component
// a --> b2 --> label
this.__a.setChild(this.__b2);
this.assertEquals(
"b2",
this.__label.getValue(),
"Deep binding does not work with updating the first parameter."
);
// check for the null value
// a --> null
this.__a.setChild(null);
this.assertNull(
this.__label.getValue(),
"Binding does not work with null."
);
},
testDepthOf3(attribute) {
// create a hierarchy
var c1 = new qx.test.MultiBinding().set({
name: "c1"
});
var c2 = new qx.test.MultiBinding().set({
name: "c2"
});
// a --> b1 --> c1 --> label
// b2 --> c2
this.__a.setChild(this.__b1);
this.__b1.setChild(c1);
this.__b2.setChild(c2);
// create the binding
qx.data.SingleValueBinding.bind(
this.__a,
"child.child.name",
this.__label,
"value"
);
// just set the name of the last component
c1.setName("C1");
this.assertEquals(
"C1",
this.__label.getValue(),
"Deep binding does not work with updating the third parameter."
);
// change the middle child
// a --> b2 --> c2 --> label
this.__a.setChild(this.__b2);
this.assertEquals(
"c2",
this.__label.getValue(),
"Deep binding does not work with updating the second parameter."
);
// set the middle child to null
// a --> null
this.__a.setChild(null);
this.assertNull(
this.__label.getValue(),
"Deep binding does not work with first null child."
);
// set only two childs
// a --> b1 --> null
this.__b1.setChild(null);
this.__a.setChild(this.__b1);
this.assertNull(
this.__label.getValue(),
"Deep binding does not work with second null child."
);
// set the childs in a row
// a --> b1 --> c1 --> label
this.__b1.setChild(c1);
this.assertEquals(
"C1",
this.__label.getValue(),
"Deep binding does not work with updating the third parameter."
);
},
testDepthOf5(attribute) {
// create a hierarchy
var c = new qx.test.MultiBinding().set({
name: "c"
});
var d = new qx.test.MultiBinding().set({
name: "d"
});
var e = new qx.test.MultiBinding().set({
name: "e"
});
// a --> b1 --> c --> d --> e --> label
this.__a.setChild(this.__b1);
this.__b1.setChild(c);
c.setChild(d);
d.setChild(e);
// create the binding
qx.data.SingleValueBinding.bind(
this.__a,
"child.child.child.child.name",
this.__label,
"value"
);
// test if the binding did work
this.assertEquals(
"e",
this.__label.getValue(),
"Deep binding does not work with updating the third parameter."
);
},
testWrongDeep() {
// create a hierarchy
this.__a.setChild(this.__b1);
var a = this.__a;
var label = this.__label;
// only in source version
if (qx.core.Environment.get("qx.debug")) {
// set a wrong first parameter in the chain
this.assertException(
function () {
qx.data.SingleValueBinding.bind(a, "chiild.name", label, "value");
},
qx.core.AssertionError,
null,
"Wrong property name."
);
// set a complete wrong chain
this.assertException(
function () {
qx.data.SingleValueBinding.bind(a, "affe", label, "value");
},
qx.core.AssertionError,
null,
"Wrong property name."
);
}
},
testSingle() {
// set only one property in the chain
qx.data.SingleValueBinding.bind(this.__a, "name", this.__label, "value");
// chech the initial value
this.assertEquals(
"a",
this.__label.getValue(),
"Single property names don't work!"
);
// check the binding
this.__a.setName("A");
this.assertEquals(
"A",
this.__label.getValue(),
"Single property names don't work!"
);
},
testDebug(attribute) {
// build the structure
this.__a.setChild(this.__b1);
// bind the stuff together
var id = qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
// log this binding in the console
qx.data.SingleValueBinding.showBindingInLog(this.__a, id);
},
testRemove() {
// build the structure
this.__a.setChild(this.__b1);
// bind the stuff together
var id = qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
// check the binding
this.__b1.setName("A");
this.assertEquals(
"A",
this.__label.getValue(),
"Single property names don't work!"
);
// remove the binding
qx.data.SingleValueBinding.removeBindingFromObject(this.__a, id);
// check the binding again
this.__a.setName("A2");
this.assertEquals(
"A",
this.__label.getValue(),
"Removing does not work!"
);
// smoke Test for the remove
qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
qx.data.SingleValueBinding.bind(
this.__a,
"child.name",
this.__label,
"value"
);
},
testArrayDeep() {
this.__a.getArray().dispose();
this.__a.setArray(new qx.data.Array([this.__b1]));
this.__b1.setChild(this.__b2);
this.__b2.setChild(this.__b1);
qx.data.SingleValueBinding.bind(
this.__a,
"array[0].child.name",
this.__label,
"value"
);
this.assertEquals(
"b2",
this.__label.getValue(),
"Deep binding does not work."
);
this.__a.getArray().pop();
this.assertNull(this.__label.getValue(), "Deep binding does not work.");
this.__a.getArray().push(this.__b2);
this.assertEquals(
"b1",
this.__label.getValue(),
"Deep binding does not work."
);
this.__b1.setName("B1");
this.assertEquals(
"B1",
this.__label.getValue(),
"Deep binding does not work."
);
},
testDeepTarget() {
qx.data.SingleValueBinding.bind(this.__a, "name", this.__b1, "lab.value");
this.assertEquals(
"a",
this.__b1.getLab().getValue(),
"Deep binding on the target does not work."
);
},
testDeepTarget2() {
this.__b2.setChild(this.__b1);
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__b2,
"child.lab.value"
);
this.assertEquals(
"a",
this.__b1.getLab().getValue(),
"Deep binding on the target does not work."
);
},
testDeepTargetNull() {
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__b2,
"child.lab.value"
);
this.assertEquals(
"",
this.__b1.getLab().getValue(),
"Deep binding on the target does not work."
);
},
testDeepTargetArray() {
this.__a.getArray().dispose();
this.__a.setArray(new qx.data.Array([this.__b1]));
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__a,
"array[0].lab.value"
);
this.assertEquals(
"a",
this.__b1.getLab().getValue(),
"Deep binding on the target does not work."
);
},
testDeepTargetArrayLast() {
this.__a.getArray().dispose();
this.__a.setArray(new qx.data.Array([this.__b1]));
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__a,
"array[last].lab.value"
);
this.assertEquals(
"a",
this.__b1.getLab().getValue(),
"Deep binding on the target does not work."
);
},
testDeepTargetChange() {
var oldLabel = this.__b1.getLab();
var newLabel = new qx.test.data.singlevalue.TextFieldDummy("x");
qx.data.SingleValueBinding.bind(this.__a, "name", this.__b1, "lab.value");
this.__b1.setLab(newLabel);
this.assertEquals("a", this.__b1.getLab().getValue());
this.__a.setName("l");
this.assertEquals("a", oldLabel.getValue());
this.assertEquals("l", this.__b1.getLab().getValue());
newLabel.dispose();
oldLabel.dispose();
},
testDeepTargetChangeConverter() {
var oldLabel = this.__b1.getLab();
var newLabel = new qx.test.data.singlevalue.TextFieldDummy("x");
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__b1,
"lab.value",
{
converter(data) {
return data + "...";
}
}
);
this.__b1.setLab(newLabel);
this.assertEquals("a...", this.__b1.getLab().getValue());
this.__a.setName("l");
this.assertEquals("a...", oldLabel.getValue());
this.assertEquals("l...", this.__b1.getLab().getValue());
newLabel.dispose();
oldLabel.dispose();
},
testDeepTargetChange3() {
// set up the target chain
this.__a.setChild(this.__b1);
this.__b1.setChild(this.__b2);
this.__b2.setChild(this.__b1);
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"child.child.lab.value"
);
// check the default set
this.__label.setValue("123");
this.assertEquals("123", this.__b2.getLab().getValue());
// change the child of __a
this.__a.setChild(this.__b2);
this.assertEquals("123", this.__b1.getLab().getValue());
// set another label value
this.__label.setValue("456");
this.assertEquals("123", this.__b2.getLab().getValue());
this.assertEquals("456", this.__b1.getLab().getValue());
},
testDeepTargetChange3Remove() {
// set up the target chain
this.__a.setChild(this.__b1);
this.__b1.setChild(this.__b2);
this.__b2.setChild(this.__b1);
var id = qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"child.child.lab.value"
);
// check the default set
this.__label.setValue("123");
this.assertEquals("123", this.__b2.getLab().getValue(), "0");
qx.data.SingleValueBinding.removeBindingFromObject(this.__label, id);
// change the child of __a
this.__a.setChild(this.__b2);
this.assertEquals(
"",
this.__b1.getLab().getValue(),
"listener still there"
);
// set another label value
this.__label.setValue("456");
this.assertEquals("123", this.__b2.getLab().getValue(), "1");
this.assertEquals("", this.__b1.getLab().getValue(), "2");
},
testDeepTargetChangeArray() {
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"array[0]"
);
this.__label.setValue("123");
this.assertEquals("123", this.__a.getArray().getItem(0));
var newArray = new qx.data.Array([0, 1, 0]);
var oldArray = this.__a.getArray();
this.__a.setArray(newArray);
this.assertEquals("123", this.__a.getArray().getItem(0), "initial set");
this.__label.setValue("456");
this.assertEquals("456", newArray.getItem(0));
this.assertEquals("123", oldArray.getItem(0));
oldArray.dispose();
newArray.dispose();
},
testDeepTargetChangeArrayLast() {
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"array[last]"
);
this.__label.setValue("123");
this.assertEquals("123", this.__a.getArray().getItem(2));
var newArray = new qx.data.Array([0, 1, 0]);
var oldArray = this.__a.getArray();
this.__a.setArray(newArray);
this.assertEquals("123", this.__a.getArray().getItem(2), "initial set");
this.__label.setValue("456");
this.assertEquals("456", newArray.getItem(2));
this.assertEquals("123", oldArray.getItem(2));
oldArray.dispose();
newArray.dispose();
},
testDeepTargetChange3Array() {
// set up the target chain
this.__a.setChild(this.__b1);
this.__b1.setChild(this.__b2);
this.__b2.setChild(this.__b1);
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"child.child.array[0]"
);
// check the default set
this.__label.setValue("123");
this.assertEquals("123", this.__b2.getArray().getItem(0));
// change the child of __a
this.__a.setChild(this.__b2);
this.assertEquals("123", this.__b1.getArray().getItem(0));
// set another label value
this.__label.setValue("456");
this.assertEquals("456", this.__b1.getArray().getItem(0));
this.assertEquals(
"123",
this.__b2.getArray().getItem(0),
"binding still exists"
);
},
testDeepTargetChangeMiddleArray() {
var oldArray = this.__a.getArray();
var array = new qx.data.Array([this.__b1, this.__b2]);
this.__a.setArray(array);
oldArray.dispose();
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"array[0].lab.value"
);
this.__label.setValue("123");
this.assertEquals("123", this.__b1.getLab().getValue());
array.reverse();
this.assertEquals("123", this.__b2.getLab().getValue());
this.__label.setValue("456");
this.assertEquals("456", this.__b2.getLab().getValue());
this.assertEquals("123", this.__b1.getLab().getValue());
},
testDeepTargetChangeMiddleArrayLast() {
var oldArray = this.__a.getArray();
var array = new qx.data.Array([this.__b2, this.__b1]);
this.__a.setArray(array);
oldArray.dispose();
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"array[last].lab.value"
);
this.__label.setValue("123");
this.assertEquals("123", this.__b1.getLab().getValue());
array.reverse();
this.assertEquals("123", this.__b2.getLab().getValue());
this.__label.setValue("456");
this.assertEquals("456", this.__b2.getLab().getValue());
this.assertEquals("123", this.__b1.getLab().getValue());
},
testDeepTargetChangeWithoutEvent() {
this.__a.setChildWithout(this.__b1);
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"childWithout.name"
);
this.__label.setValue("123");
this.assertEquals("123", this.__b1.getName());
this.__a.setChildWithout(this.__b2);
this.assertEquals("b2", this.__b2.getName());
this.__label.setValue("456");
this.assertEquals("456", this.__b2.getName());
this.assertEquals("123", this.__b1.getName());
},
testDeepTargetChangeWithoutEvent3() {
this.__a.setChild(this.__b1);
this.__b1.setChildWithout(this.__b2);
this.__b2.setChildWithout(this.__b1);
qx.data.SingleValueBinding.bind(
this.__label,
"value",
this.__a,
"child.childWithout.name"
);
this.__label.setValue("123");
this.assertEquals("123", this.__b2.getName());
this.__a.setChild(this.__b2);
this.assertEquals("123", this.__b1.getName());
this.__b2.setChildWithout(this.__a);
this.assertEquals("a", this.__a.getName());
this.__label.setValue("456");
this.assertEquals("456", this.__a.getName());
this.assertEquals("123", this.__b1.getName());
},
testDeepTargetChange3ResetNotNull() {
// set up the target chain
this.__a.setChild(this.__b1);
this.__b1.setChild(this.__b2);
this.__b2.setChild(this.__b1);
this.__a.setName(null);
qx.data.SingleValueBinding.bind(
this.__a,
"name",
this.__a,
"child.child.name"
);
this.assertEquals(this.__a.getName(), this.__b2.getName());
this.__a.setName("nnnnn");
this.assertEquals(this.__a.getName(), this.__b2.getName());
this.__a.setName(null);
this.assertEquals(this.__a.getName(), this.__b2.getName());
},
/**
* Remove a deep binding that has a class in its binding that does not have a property in the chain.
*/
testRemoveIncompleteBinding() {
var source = qx.data.marshal.Json.createModel({ a: null });
var a = qx.data.marshal.Json.createModel({}); // a class that does not contain a property with name "b"
var target = qx.data.marshal.Json.createModel({ result: null });
try {
source.bind("a.b", target, "result");
source.setA(a);
source.removeAllBindings();
} catch (e) {
this.error(e);
this.assertTrue(false, e.message);
}
source = qx.data.marshal.Json.createModel({ a: null });
source.setA(a);
try {
source.bind("a.b", target, "result");
source.removeAllBindings();
} catch (e) {
this.error(e);
this.assertTrue(false, e.message);
}
}
}
});