fnGetContext = function () {
					return {
						created : function () {}
					};
				}
******************************************************************************************
	QUnit.test("fetchIfChildCanUseCache: operation binding or dependent", function (assert) {
		var oBinding = new ODataParentBinding({
				oContext : {},
				oModel : {
					getMetaModel : function () { return {}; },
					resolve : function () {}
				},
				sPath : "path"
			}),
			oContext = {
				getIndex : function () {},
				getPath : function () { return "/Foo/operation(...)/Bar/path"; }
			},
			oModelMock = this.mock(oBinding.oModel);

		this.mock(oBinding).expects("getBaseForPathReduction").withExactArgs().returns("anything");
		oModelMock.expects("resolve")
			.withExactArgs("childPath", sinon.match.same(oContext))
			.returns("/resolved/child/path");

		// code under test
		assert.strictEqual(
			oBinding.fetchIfChildCanUseCache(oContext, "childPath", null, "~bIsProperty~")
				.getResult(),
			"/resolved/child/path");
		assert.deepEqual(oBinding.mChildPathsReducedToParent, {});
		assert.deepEqual(oBinding.aChildCanUseCachePromises, [], "unchanged");
		assert.deepEqual(oBinding.mCanUseCachePromiseByChildPath, {}, "unchanged");
	});

	//*********************************************************************************************
[false, true].forEach(function (bReduced, i) {
	QUnit.test("fetchIfChildCanUseCache, operation parameter #" + i, function (assert) {
		var oMetaModel = {
				getReducedPath : function () {}
			},
			fnFetchMetadata = function () {},
			oModel = {
				getMetaModel : function () { return oMetaModel; },
				oInterface : {
					fetchMetadata : fnFetchMetadata
				},
				resolve : function () {}
			},
			oParentBinding = {
				fetchIfChildCanUseCache : function () {}
			},
			oBinding = new ODataParentBinding({
				oContext : {
					getBinding : function () { return oParentBinding; },
					getPath : function () { return "/Set('2')"; }
				},
				doFetchOrGetQueryOptions : function () {
					return SyncPromise.resolve({});
				},
				oModel : oModel,
				mParameters : {},
				sPath : "operation(...)"
			}),
			mChildQueryOptions = {},
			oChildQueryOptionsPromise = SyncPromise.resolve(Promise.resolve(mChildQueryOptions)),
			oContext = Context.create(oModel, oBinding, "/Set('2')/operation(...)/$Parameter"),
			oHelperMock = this.mock(_Helper),
			oModelMock = this.mock(oBinding.oModel),
			sPath = "foo/bar",
			oPromise;

		this.mock(oBinding).expects("getBaseForPathReduction")
			.withExactArgs().returns("/base/path");
		oModelMock.expects("resolve")
			.withExactArgs(sPath, sinon.match.same(oContext))
			.returns("/Set('2')/operation(...)/$Parameter/foo/bar");
		oHelperMock.expects("getMetaPath").withExactArgs("/Set('2')/operation(...)/$Parameter")
			.returns("/Set/operation/$Parameter");
		oHelperMock.expects("getMetaPath")
			.withExactArgs("/Set('2')/operation(...)/$Parameter/foo/bar")
			.returns("/Set/operation/$Parameter/foo/bar");
		oHelperMock.expects("fetchPropertyAndType")
			.withExactArgs(sinon.match.same(fnFetchMetadata), "/Set/operation/$Parameter/foo/bar")
			.returns(SyncPromise.resolve());
		oHelperMock.expects("clone").never();
		this.mock(oBinding).expects("selectKeyProperties").never();
		this.mock(oMetaModel).expects("getReducedPath")
			.withExactArgs("/Set('2')/operation(...)/$Parameter/foo/bar", "/base/path")
			.returns("/reduced/child/path");
		oHelperMock.expects("getMetaPath").withExactArgs("/reduced/child/path")
			.returns("/reduced/child/metapath");
		oHelperMock.expects("getRelativePath")
			.withExactArgs("/reduced/child/metapath", "/Set/operation/$Parameter")
			.returns(bReduced ? undefined : "unused");
		oHelperMock.expects("getRelativePath").exactly(bReduced ? 1 : 0)
			.withExactArgs("/Set('2')/operation(...)/$Parameter/foo/bar", "/Set('2')")
			.returns("operation(...)/$Parameter/foo/bar");
		this.mock(oParentBinding).expects("fetchIfChildCanUseCache").exactly(bReduced ? 1 : 0)
			.withExactArgs(sinon.match.same(oBinding.oContext), "operation(...)/$Parameter/foo/bar",
				sinon.match.same(mChildQueryOptions), "~bIsProperty~")
			.returns("/reduced/child/path");
		this.mock(oBinding).expects("aggregateQueryOptions").never();

		// code under test
		oPromise = oBinding.fetchIfChildCanUseCache(oContext, sPath, oChildQueryOptionsPromise,
			"~bIsProperty~");

		assert.strictEqual(oBinding.aChildCanUseCachePromises[0], oPromise);
		assert.deepEqual(Object.keys(oBinding.mCanUseCachePromiseByChildPath), []);
		return oPromise.then(function (sReducedPath) {
			assert.strictEqual(sReducedPath, "/reduced/child/path");
			assert.deepEqual(oBinding.mChildPathsReducedToParent, bReduced ? {[sPath] : true} : {});
		});
	});
});

//*********************************************************************************************
	QUnit.test("fetchIfChildCanUseCache: non-deferred function", function (assert) {
		var fnFetchMetadata = function () {},
			oBinding = new ODataParentBinding({
				doFetchOrGetQueryOptions : function () {},
				oModel : {
					getMetaModel : function () { return null; },
					oInterface : {
						fetchMetadata : fnFetchMetadata
					},
					resolve : function () {}
				},
				mParameters : {},
				sPath : "/Collection(42)"
			}),
			sChildPath = "Function(foo=42)",
			oContext = Context.create(this.oModel, oBinding, "/Collection(42)"),
			oModelMock = this.mock(oBinding.oModel),
			oPromise;

		oBinding.mCanUseCachePromiseByChildPath[""] = "~n/a~";
		this.mock(oBinding).expects("getBaseForPathReduction")
			.withExactArgs().returns("/base/path");
		oModelMock.expects("resolve")
			.withExactArgs(sChildPath, sinon.match.same(oContext))
			.returns("/resolved/child/path");
		this.mock(_Helper).expects("fetchPropertyAndType")
			.withExactArgs(sinon.match.same(fnFetchMetadata), "/resolved/child/path")
			.returns(SyncPromise.resolve([{$isBound : true, $kind : "Function"}]));
		this.mock(_Helper).expects("clone").never();
		this.mock(oBinding).expects("selectKeyProperties").never();
		this.mock(oBinding).expects("doFetchOrGetQueryOptions").withExactArgs(undefined)
			.returns(SyncPromise.resolve());

		// code under test
		oPromise = oBinding.fetchIfChildCanUseCache(oContext, sChildPath, SyncPromise.resolve());

		assert.strictEqual(oBinding.aChildCanUseCachePromises[0], oPromise);
		assert.deepEqual(oBinding.mCanUseCachePromiseByChildPath, {"" : "~n/a~"}, "unchanged");
		return oPromise.then(function (sReducedPath) {
			assert.strictEqual(sReducedPath, undefined);
			assert.deepEqual(oBinding.mChildPathsReducedToParent, {});
		});
	});

	//*********************************************************************************************
[undefined, true].forEach(function (bImmutable) {
	var sTitle = "fetchIfChildCanUseCache: non-deferred function and 'value', bImmutable = "
			+ bImmutable;

	QUnit.test(sTitle, function (assert) {
		var oCache = {
				hasSentRequest : function () { return bImmutable; },
				setQueryOptions : function () {}
			},
			oMetaModel = {
				getReducedPath : function () {}
			},
			fnFetchMetadata = function () {},
			oBinding = new ODataParentBinding({
				oCache : bImmutable ? oCache : undefined,
				oCachePromise : SyncPromise.resolve(bImmutable ? oCache : Promise.resolve(oCache)),
				doFetchOrGetQueryOptions : function () {},
				oModel : {
					getMetaModel : function () { return oMetaModel; },
					oInterface : {
						fetchMetadata : fnFetchMetadata
					},
					resolve : function () {}
				},
				mParameters : {},
				sPath : "/Function(foo=42)",
				bRelative : false
			}),
			oBindingMock = this.mock(oBinding),
			sChildPath = "value",
			oContext = Context.create(this.oModel, oBinding, "/Function(foo=42)"),
			mLocalQueryOptions = {},
			oModelMock = this.mock(oBinding.oModel),
			oPromise;

		oModelMock.expects("resolve")
			.withExactArgs(sChildPath, sinon.match.same(oContext))
			.returns("/resolved/child/path");
		this.mock(_Helper).expects("fetchPropertyAndType")
			.withExactArgs(sinon.match.same(fnFetchMetadata), "/resolved/child/path")
			.returns(SyncPromise.resolve({$isCollection : true, $Type : "some.EntityType"}));
		oBindingMock.expects("doFetchOrGetQueryOptions").withExactArgs(undefined)
			.returns(SyncPromise.resolve(mLocalQueryOptions));
		this.mock(_Helper).expects("clone").withExactArgs(sinon.match.object).returns("~clone~");
		oBindingMock.expects("selectKeyProperties")
			.withExactArgs("~clone~", "/Function"); // Note: w/o $Key nothing happens
		oBindingMock.expects("getBaseForPathReduction")
			.withExactArgs().returns("/base/path");
		this.mock(oMetaModel).expects("getReducedPath")
			.withExactArgs("/resolved/child/path", "/base/path")
			.returns("/reduced/child/path");
		this.mock(_Helper).expects("getRelativePath")
			.withExactArgs("/reduced/child/path", "/Function")
			.returns("value");
		oBindingMock.expects("aggregateQueryOptions")
			.withExactArgs({}, "/Function", bImmutable, "~bIsProperty~")
			.returns(!bImmutable);

		// code under test
		oPromise = oBinding.fetchIfChildCanUseCache(oContext, sChildPath, undefined,
			"~bIsProperty~");

		assert.strictEqual(oBinding.aChildCanUseCachePromises[0], oPromise);
		assert.strictEqual(oBinding.mCanUseCachePromiseByChildPath[sChildPath], oPromise);
		assert.deepEqual(Object.keys(oBinding.mCanUseCachePromiseByChildPath), [sChildPath]);
		return oPromise.then(function (sReducedPath) {
			assert.strictEqual(sReducedPath, bImmutable ? undefined : "/reduced/child/path");
			assert.deepEqual(oBinding.mChildPathsReducedToParent, {});
		});
	});
});

	//*********************************************************************************************
	QUnit.test("fetchIfChildCanUseCache, suspended parent binding", function (assert) {
		var oBinding = new ODataParentBinding({
				oContext : {},
				oModel : {
					getMetaModel : function () { return {}; },
					resolve : function () {}
				},
				sPath : "/TEAMS"
			}),
			oContext = {
				getIndex : function () {},
				getPath : function () { return "/TEAMS"; }
			},
			oModelMock = this.mock(oBinding.oModel);

		this.mock(oBinding).expects("getBaseForPathReduction").withExactArgs().returns("anything");
		oModelMock.expects("resolve")
			.withExactArgs("childPath", sinon.match.same(oContext))
			.returns("/resolved/child/path");
		this.mock(oBinding).expects("isRootBindingSuspended").withExactArgs().returns(true);

		assert.strictEqual(
			// code under test
			oBinding.fetchIfChildCanUseCache(oContext, "childPath", {}, "~bIsProperty~")
				.getResult(),
			"/resolved/child/path");
		assert.deepEqual(oBinding.mChildPathsReducedToParent, {});
		assert.deepEqual(oBinding.aChildCanUseCachePromises, [], "unchanged");
		assert.deepEqual(oBinding.mCanUseCachePromiseByChildPath, {}, "unchanged");
	});

	//*********************************************************************************************
	QUnit.test("fetchIfChildCanUseCache: delegate to parent binding", function (assert) {
		var oMetaModel = {
				getReducedPath : function () {}
			},
			fnFetchMetadata = function () {},
			oParentBinding = new ODataParentBinding(),
			oBinding = new ODataParentBinding({
				mCanUseCachePromiseByChildPath : {"SOITEMS_2_SO/Note" : "do not use"},
				oCache : null,
				oCachePromise : SyncPromise.resolve(Promise.resolve(null)),
				oContext : {
					getBinding : function () { return oParentBinding; },
					getPath : function () { return "/SalesOrderList('42')"; }
				},
				doFetchOrGetQueryOptions : function () {},
				isFirstCreateAtEnd : function () {},
				oModel : {
					getMetaModel : function () { return oMetaModel; },
					oInterface : {
						fetchMetadata : fnFetchMetadata
					},
					resolve : function () {}
				},
				sPath : "SO_2_SOITEMS"
			}),
			oBindingMock = this.mock(oBinding),
			sChildPath = "SOITEMS_2_SO/Note",
			mChildQueryOptions = {},
			oChildQueryOptionsPromise = SyncPromise.resolve(Promise.resolve(mChildQueryOptions)),
			oContext = Context.create(this.oModel, oBinding,
				"/SalesOrderList('42')/SO_2_SOITEMS('23')", 23),
			oHelperMock = this.mock(_Helper),
			mLocalQueryOptions = {},
			oModelMock = this.mock(oBinding.oModel),
			oPromise;

		oBinding.mChildPathsReducedToParent = {foo : true};
		oChildQueryOptionsPromise.then(function () {
			oBinding.oContext = undefined; // this might happen e.g. for a virtual parent context
		});
		oModelMock.expects("resolve")
			.withExactArgs("SOITEMS_2_SO/Note", sinon.match.same(oContext))
			.returns("/SalesOrderList('42')/SO_2_SOITEMS('23')/SOITEMS_2_SO/Note");
		oHelperMock.expects("getMetaPath")
			.withExactArgs("/SalesOrderList('42')/SO_2_SOITEMS('23')")
			.returns("/SalesOrderList/SO_2_SOITEMS");
		oHelperMock.expects("getMetaPath")
			.withExactArgs("/SalesOrderList('42')/SO_2_SOITEMS('23')/SOITEMS_2_SO/Note")
			.returns("/SalesOrderList/SO_2_SOITEMS/SOITEMS_2_SO/Note");
		oBindingMock.expects("doFetchOrGetQueryOptions")
			.withExactArgs(sinon.match.same(oBinding.oContext))
			.returns(SyncPromise.resolve(mLocalQueryOptions));
		oHelperMock.expects("fetchPropertyAndType")
			.withExactArgs(sinon.match.same(fnFetchMetadata),
				"/SalesOrderList/SO_2_SOITEMS/SOITEMS_2_SO/Note")
			.returns(SyncPromise.resolve({$kind : "Property"}));
		this.mock(_Helper).expects("clone").never();
		this.mock(oBinding).expects("selectKeyProperties").never();
		oBindingMock.expects("getBaseForPathReduction")
			.withExactArgs().returns("/SalesOrderList");
		this.mock(oMetaModel).expects("getReducedPath")
			.withExactArgs("/SalesOrderList('42')/SO_2_SOITEMS('23')/SOITEMS_2_SO/Note",
				"/SalesOrderList")
			.returns("/SalesOrderList('42')/Note");
		oHelperMock.expects("getMetaPath").withExactArgs("/SalesOrderList('42')/Note")
			.returns("/SalesOrderList/Note");
		oHelperMock.expects("getRelativePath")
			.withExactArgs("/SalesOrderList/Note", "/SalesOrderList/SO_2_SOITEMS")
			.returns(undefined);
		oHelperMock.expects("getRelativePath")
			.withExactArgs("/SalesOrderList('42')/SO_2_SOITEMS('23')/SOITEMS_2_SO/Note",
				"/SalesOrderList('42')")
			.returns("SO_2_SOITEMS('23')/SOITEMS_2_SO/Note");
		this.mock(oParentBinding).expects("fetchIfChildCanUseCache")
			.withExactArgs(sinon.match.same(oBinding.oContext),
				"SO_2_SOITEMS('23')/SOITEMS_2_SO/Note", sinon.match.same(mChildQueryOptions),
				"~bIsProperty~")
			.returns(Promise.resolve("/SalesOrderList('42')/Note"));

		// code under test
		oPromise = oBinding.fetchIfChildCanUseCache(oContext, sChildPath, oChildQueryOptionsPromise,
			"~bIsProperty~");

		assert.strictEqual(oBinding.aChildCanUseCachePromises[0], oPromise);
		assert.strictEqual(oBinding.mCanUseCachePromiseByChildPath[sChildPath], "do not use");
		assert.deepEqual(Object.keys(oBinding.mCanUseCachePromiseByChildPath), [sChildPath]);
		return oPromise.then(function (sReducedPath) {
			assert.strictEqual(sReducedPath, "/SalesOrderList('42')/Note");
			assert.deepEqual(oBinding.mChildPathsReducedToParent,
				{foo : true, [sChildPath] : true});
		});
	});

	//*********************************************************************************************
[{
	sOldReducedPath : undefined,
	sChildPath : "childPath",
	bSameMetaPath : true
}, {
	sOldReducedPath : "ignore/me",
	sChildPath : "childPath",
	bSameMetaPath : true
}, {
	sOldReducedPath : "ignore/me",
	sChildPath : "child/path",
	bSameMetaPath : true
}, {
	sOldReducedPath : "ignore/me",
	sChildPath : "child/path",
	bSameMetaPath : false
}].forEach(function (o, i) {
	QUnit.test("fetchIfChildCanUseCache: mCanUseCachePromiseByChildPath, #" + i, function (assert) {
		var oCanUseCachePromise = SyncPromise.resolve(Promise.resolve(o.sOldReducedPath)),
			oMetaModel = {
				getReducedPath : function () {}
			},
			oBinding = new ODataParentBinding({
				oCache : {}, // not null
				oContext : "do not use",
				oModel : {
					getMetaModel : function () { return oMetaModel; },
					resolve : function () {}
				}
			}),
			oContext = {
				getIndex : function () {},
				getPath : function () { return "/TEAMS"; }
			},
			sExpectedReducedPath = o.sOldReducedPath ? "/resolved/child/path" : undefined,
			oHelperMock = this.mock(_Helper),
			oPromise;

		oBinding.mCanUseCachePromiseByChildPath[o.sChildPath] = oCanUseCachePromise;
		oBinding.mChildPathsReducedToParent = "~mChildPathsReducedToParent~";
		this.mock(oBinding).expects("getBaseForPathReduction").withExactArgs()
			.returns("/base/path");
		this.mock(oBinding.oModel).expects("resolve")
			.withExactArgs(o.sChildPath, sinon.match.same(oContext))
			.returns("/resolved/child/path");
		this.mock(oBinding).expects("isRootBindingSuspended").withExactArgs().returns(false);
		this.mock(_Helper).expects("isDataAggregation").withExactArgs(undefined).returns(false);
		oHelperMock.expects("getMetaPath").never();
		if (o.sChildPath === "child/path") {
			oHelperMock.expects("getMetaPath").withExactArgs(o.sOldReducedPath).returns("A");
			oHelperMock.expects("getMetaPath").withExactArgs("/resolved/child/path")
				.returns(o.bSameMetaPath ? "A" : "B");
		}
		if (o.bSameMetaPath) {
			this.mock(oMetaModel).expects("getReducedPath").never();
		} else {
			this.mock(oMetaModel).expects("getReducedPath")
				.withExactArgs("/resolved/child/path", "/base/path").returns("/reduced/path");
			sExpectedReducedPath = "/reduced/path";
		}

		// code under test
		oPromise = oBinding.fetchIfChildCanUseCache(oContext, o.sChildPath, undefined, true);

		return oPromise.then(function (sReducedPath) {
			assert.strictEqual(sReducedPath, sExpectedReducedPath);

			// Note: we wait as long as possible to check that s.th. is unchanged
			assert.deepEqual(oBinding.mChildPathsReducedToParent, "~mChildPathsReducedToParent~",
				"unchanged");
			assert.deepEqual(oBinding.aChildCanUseCachePromises, [], "unchanged");
			assert.strictEqual(oBinding.mCanUseCachePromiseByChildPath[o.sChildPath],
				oCanUseCachePromise, "unchanged");
			assert.deepEqual(Object.keys(oBinding.mCanUseCachePromiseByChildPath), [o.sChildPath]);
		});
	});
});

	//*********************************************************************************************
[{
	aggregatedQueryOptions : {$select : ["Name", "AGE"]},
	childQueryOptions : {$select : ["Name"]},
	lateQueryOptions : {$select : ["Name"]},
	success : true,
	title : "same $select as before"
}, {
	aggregatedQueryOptions : {$select : ["Name", "AGE"]},
	childQueryOptions : {$select : ["ROOM_ID"]},
	lateQueryOptions : {$select : ["Name", "AGE", "ROOM_ID"]},
	success : true,
	title : "new property accepted and added to late properties"
}, {
	aggregatedQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id"]}}},
	childQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {}}},
	success : true,
	title : "same $expand as before"
}, {
	aggregatedQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id"]}}},
	childQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Name"]}}},
	lateQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id", "Name"]}}},
	success : true,
	title : "new $select in existing $expand"
}, {
	aggregatedQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id"]}}},
	childQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id"]}}},
	lateQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$select : ["Team_Id"]}}},
	success : true,
	title : "same $expand"
}, {
	aggregatedQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {}}},
	childQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$expand : {TEAM_2_MANAGER : {}}}}},
	lateQueryOptions : {$expand : {EMPLOYEE_2_TEAM : {$expand : {TEAM_2_MANAGER : {}}}}},
	metadata : {
		"/base/metaPath/EMPLOYEE_2_TEAM/TEAM_2_MANAGER" : {}
	},
	success : true,
	title : "new $expand in existing $expand"
}, {
	aggregatedQueryOptions : {$select : ["AGE"]},
	childQueryOptions : {
		$expand : {
			EMPLOYEE_OF_THE_WEEK : {
				$expand : {EMPLOYEE_2_MANAGER : {$select : ["Name"]}}
			}
		}
	},
	lateQueryOptions : {
		$select : ["AGE"],
		$expand : {
			EMPLOYEE_OF_THE_WEEK : {
				$expand : {EMPLOYEE_2_MANAGER : {$select : ["Name"]}}
			}
		}
	},
	metadata : {
		"/base/metaPath/EMPLOYEE_OF_THE_WEEK" : {},
		"/base/metaPath/EMPLOYEE_OF_THE_WEEK/EMPLOYEE_2_MANAGER" : {}
	},
	success : true,
	title : "new $expand, single"
}, {
	aggregatedQueryOptions : {$select : ["AGE"]},
	childQueryOptions : {
		$expand : {
			EMPLOYEE_OF_THE_WEEK : {
				$expand : {EMPLOYEE_2_EQUIPMENTS : {$select : ["Name"]}}
			}
		}
	},
	metadata : {
		"/base/metaPath/EMPLOYEE_OF_THE_WEEK" : {},
		"/base/metaPath/EMPLOYEE_OF_THE_WEEK/EMPLOYEE_2_EQUIPMENTS" : {$isCollection : true}
	},
	success : false,
	title : "new $expand, collection"
}].forEach(function (oFixture) {
	QUnit.test("aggregateQueryOptions: cache is immutable, " + oFixture.title, function (assert) {
		var mAggregatedQueryOptions = {},
			oMetaModel = {
				fetchObject : function () {}
			},
			oBinding = new ODataParentBinding({
				mAggregatedQueryOptions : mAggregatedQueryOptions,
				oCache : {},
				mLateQueryOptions : {},
				oModel : {
					getMetaModel : function () { return oMetaModel; }
				}
			}),
			oMetaModelMock = this.mock(oMetaModel);

		this.mock(_Helper).expects("clone")
			.withExactArgs(sinon.match.same(oBinding.mLateQueryOptions))
			.returns(oFixture.aggregatedQueryOptions);
		if (oFixture.metadata) {
			Object.keys(oFixture.metadata).forEach(function (sMetaPath) {
				oMetaModelMock.expects("fetchObject").withExactArgs(sMetaPath)
					.returns(SyncPromise.resolve(oFixture.metadata[sMetaPath]));
			});
		}

		assert.strictEqual(
			// code under test
			oBinding.aggregateQueryOptions(oFixture.childQueryOptions, "/base/metaPath", true),
			oFixture.success
		);
		assert.strictEqual(oBinding.mAggregatedQueryOptions, mAggregatedQueryOptions);
		assert.deepEqual(oBinding.mAggregatedQueryOptions, {}, "mAggregatedQueryOptions unchanged");
		if (oFixture.lateQueryOptions) {
			assert.strictEqual(oBinding.mLateQueryOptions, oFixture.aggregatedQueryOptions);
		}
	});
});

	//*********************************************************************************************
	QUnit.test("deleteFromCache", function (assert) {
		var oBinding = new ODataParentBinding(),
			oCache = {
				_delete : function () { throw new Error(); }
			},
			oWithCacheExpectation;

		oWithCacheExpectation = this.mock(oBinding).expects("withCache")
			.withExactArgs(sinon.match.func, "~sPath~", true).returns("~oResult~");

		assert.strictEqual(
			// code under test
			oBinding.deleteFromCache("~oGroupLock~", "EMPLOYEES('1')", "~sPath~", "~oETagEntity~",
				"~fnCallback~"),
			"~oResult~");

		this.mock(oCache).expects("_delete")
			.withExactArgs("~oGroupLock~", "EMPLOYEES('1')", "~sCachePath~", "~oETagEntity~",
				"~fnCallback~")
			.returns("~oDeleteResult~");

		assert.strictEqual(
			// code under test
			oWithCacheExpectation.firstCall.args[0](oCache, "~sCachePath~"),
			"~oDeleteResult~");
	});

	//*********************************************************************************************
	[
		{sPath : "/Employees"}, // absolute binding
		{sPath : "TEAM_2_MANAGER"}, // relative binding without context
		{sPath : "/Employees(ID='1')", oContext : {}}, // absolute binding with context (edge case)
		{sPath : "TEAM_2_MANAGER", oContext : {}} // relative binding with standard context
	].forEach(function (oFixture) {
		QUnit.test("checkUpdateInternal: " + JSON.stringify(oFixture), function (assert) {
			var bRelative = oFixture.sPath[0] !== "/",
				oCache = bRelative ? null : { /* cache