function test(vValue, sPath, bExpected) {
			assert.strictEqual(_Helper.isMissingProperty(vValue, sPath), bExpected, sPath);
		}
******************************************************************************************
	QUnit.test("wrapChildQueryOptions: empty path", function (assert) {
		var mChildQueryOptions = {};

		// code under test
		assert.strictEqual(
			_Helper.wrapChildQueryOptions("/...", "", mChildQueryOptions),
			mChildQueryOptions);
	});

	//*********************************************************************************************
	QUnit.test("wrapChildQueryOptions, returns undefined if $apply is present", function (assert) {
		var mChildQueryOptions = {
				$apply : "filter(Amount gt 3)"
			},
			oMetaModel = {
				// Note: "this" not needed, save Function#bind below
				fetchObject : function () {}
			},
			oMetaModelMock = this.mock(oMetaModel);

		oMetaModelMock.expects("fetchObject")
			.withExactArgs("/EMPLOYEES/NavigationProperty")
			.returns(SyncPromise.resolve({$kind : "NavigationProperty"}));
		oMetaModelMock.expects("fetchObject")
			.withExactArgs("/EMPLOYEES/NavigationProperty/")
			.returns(SyncPromise.resolve({}));
		this.oLogMock.expects("debug").withExactArgs(
			"Cannot wrap $apply into $expand: NavigationProperty",
			JSON.stringify(mChildQueryOptions), sClassName
		);

		// code under test
		assert.strictEqual(
			_Helper.wrapChildQueryOptions("/EMPLOYEES", "NavigationProperty", mChildQueryOptions,
				oMetaModel.fetchObject),
			undefined);
	});

	//*********************************************************************************************
	QUnit.test("wrapChildQueryOptions, child path with bound function", function (assert) {
		var oMetaModel = {
				// Note: "this" not needed, save Function#bind below
				fetchObject : function () {}
			};

		this.mock(oMetaModel).expects("fetchObject")
			.withExactArgs("/EMPLOYEES/name.space.boundFunction")
			.returns(SyncPromise.resolve({$kind : "Function"}));

		// code under test
		assert.strictEqual(
			_Helper.wrapChildQueryOptions("/EMPLOYEES", "name.space.boundFunction/Property", {},
				oMetaModel.fetchObject),
			undefined);
	});

	//*********************************************************************************************
	QUnit.test("wrapChildQueryOptions, structural property w/ query options", function (assert) {
		var oMetaModel = {
				// Note: "this" not needed, save Function#bind below
				fetchObject : function () {}
			},
			mChildLocalQueryOptions = {$apply : "filter(AGE gt 42)"};

		this.mock(oMetaModel).expects("fetchObject")
			.withExactArgs("/EMPLOYEES/Property")
			.returns(SyncPromise.resolve({$kind : "Property"}));
		this.oLogMock.expects("error").withExactArgs(
			"Failed to enhance query options for auto-$expand/$select as the child "
				+ "binding has query options, but its path 'Property' points to a "
				+ "structural property",
			JSON.stringify(mChildLocalQueryOptions), sClassName);

		// code under test
		assert.strictEqual(
			_Helper.wrapChildQueryOptions("/EMPLOYEES", "Property", mChildLocalQueryOptions,
				oMetaModel.fetchObject),
			undefined);
	});

	//*********************************************************************************************
	[{
		mQueryOptions : undefined,
		sOrderBy : undefined,
		aFilters : undefined
	}, {
		mQueryOptions : {$orderby : "bar", $select : "Name"},
		sOrderBy : undefined,
		aFilters : [undefined]
	}, {
		mQueryOptions : undefined,
		sOrderBy : "foo",
		aFilters : [""],
		oResult : {$orderby : "foo"}
	}, {
		mQueryOptions : {$orderby : "bar", $select : "Name"},
		sOrderBy : "foo,bar",
		aFilters : undefined,
		oResult : {$orderby : "foo,bar", $select : "Name"}
	}, {
		mQueryOptions : {$orderby : "bar", $select : "Name"},
		sOrderBy : "bar",
		aFilters : undefined
	}, {
		mQueryOptions : undefined,
		sOrderBy : undefined,
		aFilters : ["foo"],
		oResult : {$filter : "foo"}
	}, {
		mQueryOptions : {$filter : "bar", $select : "Name"},
		sOrderBy : undefined,
		aFilters : ["foo,bar"],
		oResult : {$filter : "foo,bar", $select : "Name"}
	}, {
		mQueryOptions : {$filter : "bar", $select : "Name"},
		sOrderBy : undefined,
		aFilters : ["bar"]
	}, {
		mQueryOptions : {$filter : "bar", $orderby : "foo", $select : "Name"},
		sOrderBy : "foo",
		aFilters : ["bar"]
	}, {
		mQueryOptions : {$filter : "foo", $orderby : "bar", $select : "Name"},
		sOrderBy : "foo,bar",
		aFilters : ["bar,baz"],
		oResult : {$filter : "bar,baz", $orderby : "foo,bar", $select : "Name"}
	}, {
		mQueryOptions : {$filter : "foo", $orderby : "bar", $select : "Name"},
		sOrderBy : "foo,bar",
		aFilters : [undefined, "bar", "qux"],
		oResult : {
			$$filterBeforeAggregate : "bar",
			$$filterOnAggregate : "qux",
			$filter : "foo",
			$orderby : "foo,bar",
			$select : "Name"
		}
	}, {
		mQueryOptions : {$filter : "foo", $orderby : "bar", $select : "Name"},
		sOrderBy : "foo,bar",
		aFilters : ["", "bar,baz"],
		oResult : {
			$$filterBeforeAggregate : "bar,baz",
			$filter : "foo",
			$orderby : "foo,bar",
			$select : "Name"
		}
	}, {
		mQueryOptions : {$filter : "foo", $orderby : "bar", $select : "Name"},
		sOrderBy : "foo,bar",
		aFilters : ["bar,baz", "foo,bar"],
		oResult : {
			$$filterBeforeAggregate : "foo,bar",
			$filter : "bar,baz",
			$orderby : "foo,bar",
			$select : "Name"
		}
	}, {
		mQueryOptions : {
			$$filterBeforeAggregate : "baz",
			$filter : "foo",
			$orderby : "bar",
			$select : "Name"
		},
		sOrderBy : "foo,bar",
		aFilters : ["bar,baz"],
		oResult : {
			$$filterBeforeAggregate : "baz",
			$filter : "bar,baz",
			$orderby : "foo,bar",
			$select : "Name"
		}
	}, {
		mQueryOptions : undefined,
		aFilters : [undefined, undefined, "qux"],
		oResult : {
			$$filterOnAggregate : "qux"
		}
	}, {
		mQueryOptions : {
			$$filterOnAggregate : "qux"
		},
		aFilters : [undefined, undefined, "qux"]
	}].forEach(function (oFixture, i) {
		QUnit.test("mergeQueryOptions, " + i, function (assert) {
			var oResult,
				sQueryOptionsJSON = JSON.stringify(oFixture.mQueryOptions);

			// code under test
			oResult = _Helper.mergeQueryOptions(oFixture.mQueryOptions, oFixture.sOrderBy,
				oFixture.aFilters);

			assert.strictEqual(JSON.stringify(oFixture.mQueryOptions), sQueryOptionsJSON);
			if ("oResult" in oFixture) {
				assert.deepEqual(oResult, oFixture.oResult, i);
			} else {
				assert.strictEqual(oResult, oFixture.mQueryOptions, i);
			}
			if (oResult) {
				assert.ok(oResult.$orderby || !("$orderby" in oResult), "$orderby");
				assert.ok(oResult.$filter || !("$filter" in oResult), "$filter");
				assert.ok(oResult.$$filterBeforeAggregate
					|| !("$$filterBeforeAggregate" in oResult), "$$filterBeforeAggregate");
				assert.ok(oResult.$$filterOnAggregate
					|| !("$$filterOnAggregate" in oResult), "$$filterOnAggregate");
			}
		});
	});

	//*********************************************************************************************
[{ // $select=Bar
	mQueryOptions : {
		$select : "Bar"
	},
	sPath : "",
	mQueryOptionsForPath : {
		$select : "Bar"
	}
}, { // mQueryOptions has to be optional
	mQueryOptions : undefined,
	sPath : "",
	mQueryOptionsForPath : {}
}, { // mQueryOptions has to be optional
	mQueryOptions : undefined,
	sPath : "FooSet",
	mQueryOptionsForPath : {}
}, { // $select=Bar
	mQueryOptions : {
		$select : "Bar"
	},
	sPath : "FooSet/WithoutExpand",
	mQueryOptionsForPath : {}
}, { // $expand(FooSet=$expand(BarSet=$select(Baz)))
	mQueryOptions : {
		$expand : {
			FooSet : {
				$expand : {
					BarSet : {
						$select : ["Baz"]
					}
				}
			}
		}
	},
	sPath : "15/FooSet('0815')/BarSet",
	mQueryOptionsForPath : {
		$select : ["Baz"]
	}
}, { // $expand(ExpandWithoutOptions)
	mQueryOptions : {
		$expand : {
			ExpandWithoutOptions : true
		}
	},
	sPath : "ExpandWithoutOptions",
	mQueryOptionsForPath : {}
}, { // $expand(FooSet=$select(Bar,Baz))
	mQueryOptions : {
		$expand : {
			FooSet : {
				$select : ["Bar", "Baz"]
			}
		}
	},
	sPath : "FooSet('0815')",
	mQueryOptionsForPath : {
		$select : ["Bar", "Baz"]
	}
}, { // $expand(FooSet=$expand(BarSet=$select(Baz)))
	mQueryOptions : {
		$expand : {
			FooSet : {
				$expand : {
					BarSet : {
						$select : ["Baz"]
					}
				}
			}
		}
	},
	// combination of key predicate and index is unrealistic ;-)
	sPath : "FooSet($uid=id-1-23)/12/BarSet",
	mQueryOptionsForPath : {
		$select : ["Baz"]
	}
}, {
	mQueryOptions : {
		$expand : {
			BarSet : {
				$select : ["Param1", "Param2"]
			}
		},
		$select : ["Param3", "Param4"]
	},
	sPath : "('42')/BarSet",
	mQueryOptionsForPath : {
		$select : ["Param1", "Param2"]
	}
}, {
	mQueryOptions : {
		$select : ["Param3", "Param4"]
	},
	sPath : "('42')",
	mQueryOptionsForPath : {
		$select : ["Param3", "Param4"]
	}
}].forEach(function (oFixture) {
	QUnit.test("getQueryOptionsForPath " + oFixture.sPath, function (assert) {
		this.mock(_Helper).expects("getMetaPath").withExactArgs(oFixture.sPath).callThrough();

		// code under test
		assert.deepEqual(
			_Helper.getQueryOptionsForPath(oFixture.mQueryOptions, oFixture.sPath),
			oFixture.mQueryOptionsForPath);
	});
});

	//*********************************************************************************************
[
	{sPath : "/foo/bar/baz", sResult : "baz"},
	{sPath : "/foo/bar('baz')", sResult : "('baz')"},
	{sPath : "/foo/bar", sResult : ""},
	{sPath : "/foo", sResult : undefined},
	{sPath : "/foo/barolo", sResult : undefined}
].forEach(function (oFixture) {
	QUnit.test("getRelativePath: " + oFixture.sPath, function (assert) {
		// code under test
		assert.strictEqual(_Helper.getRelativePath(oFixture.sPath, "/foo/bar"), oFixture.sResult);

		// code under test
		assert.strictEqual(_Helper.getRelativePath(oFixture.sPath.slice(1), "foo/bar"),
			oFixture.sResult);
	});
});

	//*********************************************************************************************
	QUnit.test("getRelativePath with empty sBasePath", function (assert) {
		// code under test
		assert.strictEqual(_Helper.getRelativePath("/Teams('42')", ""), "/Teams('42')");
		// code under test
		assert.strictEqual(_Helper.getRelativePath("Teams('42')", ""), "Teams('42')");
	});

	//*********************************************************************************************
[{
	aggregated : {$select : ["Name"]},
	additional : {$select : ["ID"]},
	result : {$select : ["Name", "ID"]},
	title : "merge $select"
}, {
	aggregated : {},
	additional : {$select : ["ID"]},
	result : {$select : ["ID"]},
	title : "add $select"
}, {
	aggregated : {$select : ["Name"]},
	additional : {},
	result : {$select : ["Name"]},
	title : "no additional $select"
}, {
	aggregated : {$select : ["ID", "Name"]},
	additional : {$select : ["ID"]},
	result : {$select : ["ID", "Name"]},
	title : "$select unchanged"
}, {
	aggregated : {foo : "bar", $select : ["ID"]},
	additional : {foo : "bar", $select : ["ID"]},
	result : {foo : "bar", $select : ["ID"]},
	title : "custom query option"
}, {
	aggregated : {},
	additional : {$expand : {foo : null}},
	result : {$expand : {foo : null}},
	title : "added $expand"
}, {
	aggregated : {$expand : {foo : null}},
	additional : {$expand : {bar : null, baz : null}},
	result : {$expand : {foo : null, bar : null, baz : null}},
	title : "added $expand path"
}].forEach(function (oFixture) {
	QUnit.test("aggregateExpandSelect: " + oFixture.title, function (assert) {
		// code under test
		_Helper.aggregateExpandSelect(oFixture.aggregated, oFixture.additional);

		assert.deepEqual(oFixture.aggregated, oFixture.result);
	});
});

	//*********************************************************************************************
	QUnit.test("hasPathPrefix", function (assert) {
		var oHelperMock = this.mock(_Helper);

		oHelperMock.expects("getRelativePath").withExactArgs("sPath", "sBasePath")
			.returns(undefined);

		// code under test
		assert.strictEqual(_Helper.hasPathPrefix("sPath", "sBasePath"), false);

		oHelperMock.expects("getRelativePath").withExactArgs("sPath", "sBasePath").returns("");

		// code under test
		assert.strictEqual(_Helper.hasPathPrefix("sPath", "sBasePath"), true);
	});

	//*********************************************************************************************
	QUnit.test("hasPathSuffix", function (assert) {
		// code under test
		assert.strictEqual(_Helper.hasPathSuffix("/some/path", "path"), true);

		// code under test
		assert.strictEqual(_Helper.hasPathSuffix("/some/path", "ath"), false);

		// code under test
		assert.strictEqual(_Helper.hasPathSuffix("/some(42)/path", "(42)/path"), true);
	});
	//TODO offer _Helper.getBasePath as well?

	//*********************************************************************************************
	QUnit.test("aggregateExpandSelect: recursion", function () {
		var mAggregatedQueryOptions = {$expand : {foo : {}}},
			oHelperMock = this.mock(_Helper),
			mQueryOptions = {$expand : {foo : {}}};

		oHelperMock.expects("aggregateExpandSelect")
			.withExactArgs(sinon.match.same(mAggregatedQueryOptions),
				sinon.match.same(mQueryOptions))
			.callThrough(); // start the recursion
		oHelperMock.expects("aggregateExpandSelect")
			.withExactArgs(sinon.match.same(mAggregatedQueryOptions.$expand.foo),
				sinon.match.same(mQueryOptions.$expand.foo));

		_Helper.aggregateExpandSelect(mAggregatedQueryOptions, mQueryOptions);
	});

	//*********************************************************************************************
	QUnit.test("trampoline properties", function (assert) {
		assert.strictEqual(_Helper.deepEqual, deepEqual);
		assert.strictEqual(_Helper.merge, merge);
		assert.strictEqual(_Helper.uid, uid);
	});

	//*********************************************************************************************
[{
	// no $kind
}, {
	$kind : "Property"
}, {
	$kind : "NavigationProperty"
}].forEach(function (oFixture, i) {
	QUnit.test("fetchPropertyAndType: " + i, function (assert) {
		var oExpectedResult = oFixture.$kind ? {$kind : oFixture.$kind} : undefined,
			oMetaModel = {
				fetchObject : function () {}
			},
			oMetaModelMock = this.mock(oMetaModel),
			oPromise,
			oSyncPromise = SyncPromise.resolve(oExpectedResult);

		oMetaModelMock.expects("fetchObject")
			.withExactArgs("/resolved/child/metaPath")
			.returns(oSyncPromise);

		if (oFixture.$kind === "NavigationProperty") {
			oMetaModelMock.expects("fetchObject")
				.withExactArgs("/resolved/child/metaPath/")
				.returns(SyncPromise.resolve());
		}

		// code under test
		oPromise = _Helper.fetchPropertyAndType(oMetaModel.fetchObject, "/resolved/child/metaPath");

		assert.strictEqual(oPromise.getResult(), oExpectedResult);
	});
});

	//*********************************************************************************************
	QUnit.test("extractMergeableQueryOptions", function (assert) {
		var mQueryOptions;

		// code under test
		assert.deepEqual(_Helper.extractMergeableQueryOptions({}), {});

		// code under test
		assert.deepEqual(_Helper.extractMergeableQueryOptions({$count : true}), {});

		mQueryOptions = {$expand : "expand"};
		// code under test
		assert.deepEqual(_Helper.extractMergeableQueryOptions(mQueryOptions), {$expand : "expand"});
		assert.deepEqual(mQueryOptions, {$expand : "~"});

		mQueryOptions = {$select : "select"};
		// code under test
		assert.deepEqual(_Helper.extractMergeableQueryOptions(mQueryOptions), {$select : "select"});
		assert.deepEqual(mQueryOptions, {$select : "~"});

		mQueryOptions = {
			$count : true,
			$expand : "expand",
			$select : "select"
		};
		// code under test
		assert.deepEqual(_Helper.extractMergeableQueryOptions(mQueryOptions), {
			$expand : "expand",
			$select : "select"
		});
		assert.deepEqual(mQueryOptions, {
			$count : true,
			$expand : "~",
			$select : "~"
		});
	});

	//*********************************************************************************************
	QUnit.test("createMissing: simple properties", function (assert) {
		var oObject = {bar : undefined};

		// code under test
		_Helper.createMissing(oObject, ["bar"]);

		assert.deepEqual(oObject, {bar : undefined});

		assert.throws(function () {
			// code under test
			_Helper.createMissing(oObject, ["bar", "invalid"]);
		}, TypeError);

		// code under test
		_Helper.createMissing(oObject, ["foo"]);

		assert.deepEqual(oObject, {bar : undefined, foo : undefined, "foo@$ui5.noData" : true});

		// code under test (idempotency)
		_Helper.createMissing(oObject, ["foo"]);

		assert.deepEqual(oObject, {bar : undefined, foo : undefined, "foo@$ui5.noData" : true});

		assert.throws(function () {
			// code under test
			_Helper.createMissing(oObject, ["foo", "invalid"]);
		}, TypeError);
	});

	//*********************************************************************************************
	QUnit.test("createMissing: paths", function (assert) {
		var oEmpty = {},
			oObject = {foo : oEmpty};

		// code under test
		_Helper.createMissing(oObject, ["foo"]);

		assert.deepEqual(oObject, {foo : {}});
		assert.strictEqual(oObject.foo, oEmpty);

		// code under test
		_Helper.createMissing(oObject, ["foo", "bar"]);

		assert.deepEqual(oObject, {foo : {bar : undefined, "bar@$ui5.noData" : true}});
		assert.strictEqual(oObject.foo, oEmpty, "originally empty object has been modified");

		assert.throws(function () {
			// code under test
			_Helper.createMissing(oObject, ["foo", "bar", "invalid"]);
		}, TypeError);

		// code under test
		_Helper.createMissing(oObject, ["a", "b", "c"]);

		assert.deepEqual(oObject, {
			a : {
				b : {
					c : undefined,
					"c@$ui5.noData" : true
				}
			},
			foo : {
				bar : undefined,
				"bar@$ui5.noData" : true
			}
		});
	});

	//*********************************************************************************************
	QUnit.test("inheritPathValue: simple properties", function (assert) {
		var oSource = {bar : "<bar>", foo : "<foo>", qux : "<qux>", "qux@$ui5.noData" : "true"},
			sSource = JSON.stringify(oSource),
			oTarget = {bar : undefined};

		// code under test
		_Helper.inheritPathValue(["foo"], oSource, oTarget);

		assert.deepEqual(oTarget, {bar : undefined, foo : "<foo>"});

		// code under test
		_Helper.inheritPathValue(["bar"], oSource, oTarget);

		assert.deepEqual(oTarget, {bar : undefined, foo : "<foo>"});

		// code under test
		_Helper.inheritPathValue(["qux"], oSource, oTarget);

		assert.deepEqual(oTarget,
			{bar : undefined, foo : "<foo>", qux : "<qux>", "qux@$ui5.noData" : true});
		assert.strictEqual(JSON.stringify(oSource), sSource, "unchanged");
	});

	//*********************************************************************************************
	QUnit.test("inheritPathValue: paths", function (assert) {
		var oEmpty = {},
			oSource = {
				foo : {
					bar : "<bar>",
					qux : "<qux>", "qux@$ui5.noData" : "true"
				}
			},
			sSource = JSON.stringify(oSource),
			oTarget0 = {},
			oTarget1 = {
				foo : oEmpty
			},
			oTarget2 = {
				foo : {
					bar : undefined
				}
			};

		// code under test
		_Helper.inheritPathValue(["foo", "bar"], oSource, oTarget0);

		assert.deepEqual(oTarget0, {
			foo : {
				bar : "<bar>"
			}
		});

		// code under test
		_Helper.inheritPathValue(["foo", "baz"], oSource, oTarget0);

		assert.deepEqual(oTarget0, {
			foo : {
				bar : "<bar>",
				baz : undefined // we don't care that "baz" was actually missing in source
			}
		});

		// code under test
		_Helper.inheritPathValue(["foo", "bar"], oSource, oTarget1);

		assert.deepEqual(oTarget1, {
			foo : {
				bar : "<bar>"
			}
		});
		assert.strictEqual(oTarget1.foo, oEmpty, "originally empty object has been modified");

		// code under test
		_Helper.inheritPathValue(["foo", "bar"], oSource, oTarget2);

		assert.deepEqual(oTarget2, {
			foo : {
				bar : undefined
			}
		});

		// code under test
		_Helper.inheritPathValue(["foo", "qux"], oSource, oTarget2);

		assert.deepEqual(oTarget2, {
			foo : {
				bar : undefined,
				qux : "<qux>", "qux@$ui5.noData" : true
			}
		});

		assert.strictEqual(JSON.stringify(oSource), sSource, "unchanged");
	});

	//*********************************************************************************************
	QUnit.test("inheritPathValue: errors", function (assert) {
		var oSource = {
				foo : {
					bar : "<bar>"
				}
			};

		assert.throws(function () {
			// code under test
			_Helper.inheritPathValue(["foo", "bar"], oSource, {foo : null});
		}, TypeError);

		assert.throws(function () {
			// code under test
			_Helper.inheritPathValue(["bar", "foo"], oSource, {});
		}, TypeError);
	});

	//*********************************************************************************************
	QUnit.test("inheritPathValue: bTolerateNull", function (assert) {
		var oSource = {
				bar : "n/a",
				foo : {
					bar : "<bar>"
				}
			},
			oTarget = {
				foo : null
			};

		// code under test
		_Helper.inheritPathValue(["foo", "bar"], oSource, oTarget, true);

		assert.deepEqual(oTarget, {
			foo : {
				bar : "<bar>"
			}
		});
	});

	//*********************************************************************************************
	QUnit.test("insert", function (assert) {
		const aElements = [1, 2, 3];

		// code under test
		_Helper.insert(aElements, 1, 42);

		assert.deepEqual(aElements, [1, 42, 2, 3]);

		// code under test
		_Helper.insert(aElements, 0, 0);

		assert.deepEqual(aElements, [0, 1, 42, 2, 3]);

		// code under test
		_Helper.insert(aElements, 5, 4);

		assert.deepEqual(aElements, [0, 1, 42, 2, 3, 4]);

		// code under test
		_Helper.insert(aElements, 10, 99);

		assert.deepEqual(aElements, [0, 1, 42, 2, 3, 4,,,,, 99]);
	});

	//*********************************************************************************************
	QUnit.test("decomposeError: w/o ContentID, w/o details, w/o target", function (assert) {
		var oError = new Error("Message"),
			aErrors;

		oError.error = {message : "Top level message"};
		oError.status = 500;
		oError.statusText = "Internal Server Error";
		oError.strictHandlingFailed = true;

		this.mock(_Helper).expects("getContentID").withExactArgs(sinon.match.same(oError.error))
			.returns(undefined);

		// code under test
		aErrors = _Helper.decomposeError(oError, [{
				$ContentID : "0.0",
				$resourcePath : "~path0~",
				url : "~url0~"
			}, {
				$ContentID : "1.0",
				$resourcePath : "~path1~",
				url : "~url1~"
			}], "~serviceURL~/");

		assert.strictEqual(aErrors.length, 2);
		checkClonedError(assert, oError, aErrors[0], {
				message : "Top level message"
			}, "~serviceURL~/~url0~", "~path0~", true);
		checkClonedError(assert, oError, aErrors[1], {
				message : "Top level message",
				$ignoreTopLevel : true
			}, "~serviceURL~/~url1~", "~path1~", true);
	});

	//*********************************************************************************************
["n/a", ""].forEach(function (sTarget) {
	var sTitle = "decomposeError: w/o ContentID, w/ details, w/ + w/o target, top level target: "
			+ sTarget;

	QUnit.test(sTitle, function (assert) {
		var oError = new Error("Message"),
			aErrors,
			oHelperMock = this.mock(_Helper);

		oError.error = {
			message : "Top level message",
			target : sTarget,
			details : [{
				foo : "bar",
				message : "A Message",
				target : "n/a"
			}, {
				foo : "baz",
				message : "Another Message"
			}, {
				foo : "barbaz",
				message : "Yet another Message",
				target : ""
			}]
		};
		oError.status = 500;
		oError.statusText = "Internal Server Error";
		oHelperMock.expects("getContentID").withExactArgs(sinon.match.same(oError.error))
			.returns(undefined);
		oHelperMock.expects("getContentID").withExactArgs(oError.error.details[0])
			.returns(undefined);
		oHelperMock.expects("getContentID").withExactArgs(oError.error.details[1])
			.returns(undefined);
		oHelperMock.expects("getContentID").withExactArgs(oError.error.details[2])
			.returns(undefined);

		// code under test
		aErrors = _Helper.decomposeError(oError, [{
				$ContentID : "0.0",
				$resourcePath : "~path0~",
				url : "~url0~"
			}, {
				$ContentID : "1.0",
				$resourcePath : "~path1~",
				url : "~url1~"
			}, {
				$ContentID : "2.0",
				$resourcePath : "~path2~",
				url : "~url2~"
			}], "~serviceURL~/");

		assert.strictEqual(aErrors.length, 3);
		checkClonedError(assert, oError, aErrors[0], {
				message : sTarget ? "n/a: Top level message" : "Top level message",
				details : [{
					foo : "bar",
					message : "n/a: A Message"
				}, {
					foo : "baz",
					message : "Another Message"
				}, {
					foo : "barbaz",
					message : "Yet another Message"
				}]
			}, "~serviceURL~/~url0~", "~path0~");
		checkClonedError(assert, oError, aErrors[1], {
				message : "Top level message",
				target : sTarget,
				details : [],
				$ignoreTopLevel : true
			}, "~serviceURL~/~url1~", "~path1~");
		checkClonedError(assert, oError, aErrors[2], {
				message : "Top level message",
				target : sTarget,
				details : [],
				$ignoreTopLevel : true
			}, "~serviceURL~/~url2~", "~path2~");
	});
});

	//*********************************************************************************************
	QUnit.test("decomposeError: w/ ContentID", function (assert) {
		var oError = new Error("Message"),
			aErrors,
			oHelperMock = this.mock(_Helper);

		oError.error = {
			message : "Top level message",
			"@SAP__core.ContentID" : "1.0",
			details : [{
				message : "A message",
				"@SAP__core.ContentID" : "1.0"
			}]
		};
		oError.status = 500;
		oError.statusText = "Internal Server Error";
		oError.strictHandlingFailed = true;
		oHelperMock.expects("getContentID").withExactArgs(sinon.match.same(oError.error))
			.callThrough();
		oHelperMock.expects("getContentID").withExactArgs(oError.error.details[0])
			.callThrough();

		// code under test
		aErrors = _Helper.decomposeError(oError, [{
				$ContentID : "0.0",
				$resourcePath : "~path0~",
				url : "~url0~"
			}, {
				$ContentID : "1.0",
				$resourcePath : "~path1~",
				url : "~url1~"
			}], "~serviceURL~/");

		assert.strictEqual(aErrors.length, 2);
		checkClonedError(assert, oError, aErrors[0], {
				message : "Top level message",
				"@SAP__core.ContentID" : "1.0",
				$ignoreTopLevel : true,
				details : []
			}, "~serviceURL~/~url0~", "~path0~", true);
		checkClonedError(assert, oError, aErrors[1], {
				message : "Top level message",
				"@SAP__core.ContentID" : "1.0",
				details : [{
					message : "A message",
					"@SAP__core.ContentID" : "1.0"
				}]
			}, "~serviceURL~/~url1~", "~path1~", true);
	});

	//*********************************************************************************************
	QUnit.test("getAnnotation: success", function (assert) {
		var oMessage = {"~key~" : "~value~"};

		this.mock(_Helper).expects("getAnnotationKey")
			.withExactArgs(sinon.match.same(oMessage), "~sName~").returns("~key~");

		// code under test
		assert.strictEqual(_Helper.getAnnotation(oMessage, "~sName~"), "~value~");
	});

	//*********************************************************************************************
	QUnit.test("getAnnotation: failure", function (assert) {
		var oMessage = {undefined : "~value~"};

		this.mock(_Helper).expects("getAnnotationKey")
			.withExactArgs(sinon.match.same(oMessage), "~sName~").returns(undefined);

		// code under test
		assert.strictEqual(_Helper.getAnnotation(oMessage, "~sName~"), undefined);
	});

	//*********************************************************************************************
	QUnit.test("getAnnotationKey", function (assert) {
		// code under test
		assert.strictEqual(_Helper.getAnnotationKey({}, ".AnyAnnotation"), undefined,
			"empty object");

		// code under test
		assert.strictEqual(
			_Helper.getAnnotationKey({"@Foo.NotAnyAnnotation" : "n/a"}, ".AnyAnnotation"),
			undefined, "wrong term");

		// code under test
		assert.strictEqual(_Helper.getAnnotationKey({"@Foo.Bar" : "n/a"}, "bar"), undefined,
			"case matters");

		// code under test
		assert.strictEqual(
			_Helper.getAnnotationKey({"foo@Core.AnyAnnotation" : "n/a"}, ".AnyAnnotation"),
			undefined, "wrong property");

		// code under test
		assert.strictEqual(
			_Helper.getAnnotationKey({"foo@Core.AnyAnnotation" : "1.0"}, ".AnyAnnotation", "foo"),
			"foo@Core.AnyAnnotation", "success");

		// code under test
		assert.strictEqual(
			_Helper.getAnnotationKey({"@SAP__core.AnyAnnotation" : "1.0"}, ".AnyAnnotation"),
			"@SAP__core.AnyAnnotation", "underscores welcome");

		// code under test
		assert.strictEqual(
			_Helper.getAnnotationKey({"foo@Org.OData.Core.V1.AnyAnnotation" : "3.2"},
				".AnyAnnotation", "foo"),
			"foo@Org.OData.Core.V1.AnyAnnotation", "namespace, not alias");

		this.oLogMock.expects("warning")
			.withExactArgs("Cannot distinguish @Core.AnyAnnotation from @Foo.AnyAnnotation",
				undefined, sClassName);
		this.oLogMock.expects("warning")
			.withExactArgs("Cannot distinguish @Foo.AnyAnnotation from @SAP__core.AnyAnnotation",
				undefined, sClassName);

		// code under test
		assert.strictEqual(_Helper.getAnnotationKey({
				"@Core.AnyAnnotation" : "1.0",
				"@Foo.AnyAnnotation" : "1.0",
				"@SAP__core.AnyAnnotation" : "1.0"
			}, ".AnyAnnotation"), undefined, "multiple alias");
	});

	//*********************************************************************************************
	QUnit.test("getContentID", function (assert) {
		var oMessage = {};

		this.mock(_Helper).expects("getAnnotation")
			.withExactArgs(sinon.match.same(oMessage), ".ContentID")
			.returns("~ContentID~");

		assert.strictEqual(_Helper.getContentID(oMessage), "~ContentID~");
	});

	//*********************************************************************************************
	QUnit.test("getAdditionalTargets", function (assert) {
		var oMessage = {};

		this.mock(_Helper).expects("getAnnotation")
			.withExactArgs(sinon.match.same(oMessage), ".additionalTargets")
			.returns("~additionalTargets~");

		assert.strictEqual(_Helper.getAdditionalTargets(oMessage), "~additionalTargets~");
	});

	//*********************************************************************************************
	QUnit.test("filterPaths", function (assert) {
		var aPaths = ["/foo", "/bar/baz"];

		// code under test
		assert.deepEqual(_Helper.filterPaths(aPaths, ["/baz/qux"]), ["/baz/qux"]);

		// code under test
		assert.deepEqual(_Helper.filterPaths(aPaths, ["/foo"]), []);

		// code under test
		assert.deepEqual(_Helper.filterPaths(aPaths, ["/foobar", "/bar/baz/qux"]),
			["/foobar"]);

		// code under test
		assert.deepEqual(_Helper.filterPaths(aPaths, ["/bar(42)/baz", "/qux"]), ["/qux"]);
	});

	//*********************************************************************************************
	QUnit.test("adjustTargetsInError: technical error", function () {
		var oError = {};

		this.mock(_Helper).expects("adjustTargets").never();

		// code under test
		_Helper.adjustTargetsInError(oError, "oOperationMetadata", "sParameterContextPath",
			"sContextPath");
	});

	//*********************************************************************************************
	QUnit.test("adjustTargetsInError: no details", function () {
		var oError = {error : {}};

		this.mock(_Helper).expects("adjustTargets")
			.withExactArgs(sinon.match.same(oError.error), "oOperationMetadata",
				"sParameterContextPath", "sContextPath");

		// code under test
		_Helper.adjustTargetsInError(oError, "oOperationMetadata", "sParameterContextPath",
			"sContextPath");
	});

	//*********************************************************************************************
	QUnit.test("adjustTargetsInError: with details", function () {
		var oDetail0 = {},
			oDetail1 = {},
			oError = {
				error : {
					details : [oDetail0, oDetail1]
				}
			},
			oHelperMock = this.mock(_Helper);

		oHelperMock.expects("adjustTargets")
			.withExactArgs(sinon.match.same(oError.error), "oOperationMetadata",
				"sParameterContextPath", "sContextPath");
		oHelperMock.expects("adjustTargets")
			.withExactArgs(sinon.match.same(oDetail0), "oOperationMetadata",
				"sParameterContextPath", "sContextPath");
		oHelperMock.expects("adjustTargets")
			.withExactArgs(sinon.match.same(oDetail1), "oOperationMetadata",
					"sParameterContextPath", "sContextPath");

		// code under test
		_Helper.adjustTargetsInError(oError, "oOperationMetadata", "sParameterContextPath",
			"sContextPath");
	});

	//*********************************************************************************************
	QUnit.test("adjustTargets: no target", function (assert) {
		var oMessage = {};

		this.mock(_Helper).expects("getAnnotationKey")
			.withExactArgs(sinon.match.same(oMessage), ".additionalTargets")
			.returns(undefined);
		this.mock(_Helper).expects("getAdjustedTarget").never();

		// code under test
		_Helper.adjustTargets(oMessage, "oOperationMetadata", "sParameterContextPath",
			"sContextPath", "sOriginalResourcePath");

		assert.deepEqual(oMessage, {target : undefined});
	});

	//*********************************************************************************************
	QUnit.test("adjustTargets: without additional targets", function (assert) {
		var oMessage = {target : "target"};

		this.mock(_Helper).expects("getAnnotationKey")
			.withExactArgs(sinon.match.same(oMessage), ".additionalTargets")
			.returns(undefined);
		this.mock(_Helper).expects("getAdjustedTarget")
			.withExactArgs("target", "oOperationMetadata", "sParameterContextPath", "sContextPath",
				"sOriginalResourcePath")
			.returns("~adjusted~");

		// code under test
		_Helper.adjustTargets(oMessage, "oOperationMetadata", "sParameterContextPath",
			"sContextPath", "sOriginalResourcePath");

		assert.deepEqual(oMessage, {target : "~adjusted~"});
	});

	//*********************************************************************************************
[true, false].forEach(function (bTargetIsValid) {
	[true, false].forEach(function (bAnnotation) {
	var sTitle = "adjustTargets: with additional targets, annotation: " + bAnnotation
			+ ", target is valid: " + bTargetIsValid;

	QUnit.test(sTitle, function (assert) {
		var oHelperMock = this.mock(_Helper),
			oMessage;

		if (bAnnotation) {
			oMessage = {
				target : "target",
				"@foo.additionalTargets" : ["additional1", "foo", "additional2"]
			};

			oHelperMock.expects("getAnnotationKey")
				.withExactArgs(sinon.match.same(oMessage), ".additionalTargets")
				.returns("@foo.additionalTargets");
		} else {
			oMessage = {
				target : "target",
				additionalTargets : ["additional1", "foo", "additional2"],
				"@foo.additionalTargets" : "n/a" // additionalTargets must win!
			};

			oHelperMock.expects("getAnnotationKey").never();
		}
		oHelperMock.expects("getAdjustedTarget")
			.withExactArgs("target", "oOperationMetadata", "sParameterContextPath", "sContextPath",
				"sOriginalResourcePath")
			.returns(bTargetIsValid ? "~adjusted~" : undefined);
		oHelperMock.expects("getAdjustedTarget")
			.withExactArgs("additional1", "oOperationMetadata", "sParameterContextPath",
				"sContextPath", "sOriginalResourcePath")
			.returns("~adjusted1~");
		oHelperMock.expects("getAdjustedTarget")
			.withExactArgs("foo", "oOperationMetadata", "sParameterContextPath",
				"sContextPath", "sOriginalResourcePath")
			.returns(undefined);
		oHelperMock.expects("getAdjustedTarget")
			.withExactArgs("additional2", "oOperationMetadata", "sParameterContextPath",
				"sContextPath", "sOriginalResourcePath")
			.returns("~adjusted2~");

		// code under test
		_Helper.adjustTargets(oMessage, "oOperationMetadata", "sParameterContextPath",
			"sContextPath", "sOriginalResourcePath");

		const oExpectedMessage = {
			target : bTargetIsValid ? "~adjusted~" : "~adjusted1~",
			"@foo.additionalTargets" : "n/a"
		};
		const aAdditionalTargets
			= bTargetIsValid ? ["~adjusted1~", "~adjusted2~"] : ["~adjusted2~"];

		if (bAnnotation) {
			oExpectedMessage["@foo.additionalTargets"] = aAdditionalTargets;
		} else {
			oExpectedMessage.additionalTargets = aAdditionalTargets;
		}
		assert.deepEqual(oMessage, oExpectedMessage);
	});
});
});

	//*********************************************************************************************
	QUnit.test("getAdjustedTarget: unbound operation", function (assert) {
		var oOperationMetadata = {
				$Parameter : [{$Name : "baz"}, {$Name : "foo"}]
			};

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("bar", oOperationMetadata, "~parameterContextPath~"),
			undefined);

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("foo", oOperationMetadata, "~parameterContextPath~"),
			"~parameterContextPath~/foo");

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("foo/bar", oOperationMetadata, "~parameterContextPath~"),
			"~parameterContextPath~/foo/bar");

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("$Parameter/foo/bar", oOperationMetadata,
				"~parameterContextPath~", "n/a", "n/a"),
			"~parameterContextPath~/foo/bar");

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("foo/bar", oOperationMetadata),
			"foo/bar");
	});

	//*********************************************************************************************
	QUnit.test("getAdjustedTarget: bound operation", function (assert) {
		var oOperationMetadata = {
				$IsBound : true,
				$Parameter : [{$Name : "foo"}]
			};

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("$Parameter/foo/bar", oOperationMetadata,
				"~parameterContextPath~", "~contextPath~", "n/a"),
			"~contextPath~/bar");

		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("$Parameter/bar", oOperationMetadata,
				"~parameterContextPath~", "~contextPath~", "n/a"),
			undefined);
	});

	//*********************************************************************************************
	QUnit.test("getAdjustedTarget: R.V.C.", function (assert) {
		assert.strictEqual(
			// code under test
			_Helper.getAdjustedTarget("foo/bar", /*oOperationMetadata