function localTest(sNumber, bValue) {
			assert.strictEqual(_Helper.isSafeInteger(sNumber), bValue, sNumber);
		}
******************************************************************************************
	QUnit.module("sap.ui.model.odata.v4.lib._Helper", {
		beforeEach : function () {
			this.oLogMock = this.mock(Log);
			this.oLogMock.expects("warning").never();
			this.oLogMock.expects("error").never();
		}
	});

	//*********************************************************************************************
	QUnit.test("createGetMethod, not throwing", function (assert) {
		var aArguments = ["foo", "bar"],
			oResult = {},
			oSyncPromise = SyncPromise.resolve(oResult),
			oContext = {
				fetch : function () {
					assert.strictEqual(this, oContext);
					assert.deepEqual(Array.prototype.slice.call(arguments), aArguments);
					return oSyncPromise;
				}
			},
			fnGet;

		// code under test
		// Note: passing the function's name instead of reference allows for dynamic dispatch, thus
		// making a mock for "fetch*" possible in the first place
		fnGet = _Helper.createGetMethod("fetch");

		assert.strictEqual(fnGet.apply(oContext, aArguments), oResult);
		this.mock(oSyncPromise).expects("isFulfilled").returns(false);
		assert.strictEqual(fnGet.apply(oContext, aArguments), undefined);
	});

	//*********************************************************************************************
	QUnit.test("createGetMethod, throwing", function (assert) {
		var aArguments = ["foo", "bar"],
			oResult = {},
			oSyncPromise = SyncPromise.resolve(oResult),
			oContext = {
				fetch : function () {
					assert.strictEqual(this, oContext);
					assert.deepEqual(Array.prototype.slice.call(arguments), aArguments);
					return oSyncPromise;
				}
			},
			fnGet,
			oSyncPromiseMock = this.mock(oSyncPromise);

		// code under test
		fnGet = _Helper.createGetMethod("fetch", true);

		// fulfilled
		assert.strictEqual(fnGet.apply(oContext, aArguments), oResult);

		// pending
		oSyncPromiseMock.expects("isFulfilled").returns(false);
		oSyncPromiseMock.expects("isRejected").returns(false);
		assert.throws(function () {
			fnGet.apply(oContext, aArguments);
		}, new Error("Result pending"));

		// verify and restore
		oSyncPromiseMock.verify();
		oSyncPromiseMock = this.mock(oSyncPromise);

		// rejected
		oSyncPromiseMock.expects("isFulfilled").returns(false);
		oSyncPromiseMock.expects("isRejected").returns(true);
		oSyncPromiseMock.expects("caught");
		assert.throws(function () {
			fnGet.apply(oContext, aArguments);
		}, oResult);
	});

	//*********************************************************************************************
	QUnit.test("createRequestMethod", function (assert) {
		var aArguments = ["foo", "bar"],
			oResult = {},
			oSyncPromise = SyncPromise.resolve(),
			oContext = {
				fetch : function () {
					assert.strictEqual(this, oContext);
					assert.deepEqual(Array.prototype.slice.call(arguments), aArguments);
					return oSyncPromise;
				}
			},
			fnRequest;

		this.mock(Promise).expects("resolve")
			.withExactArgs(sinon.match.same(oSyncPromise)).returns(oResult);

		// code under test
		fnRequest = _Helper.createRequestMethod("fetch");

		assert.strictEqual(fnRequest.apply(oContext, aArguments), oResult);

		Promise.resolve.restore();
	});

	//*********************************************************************************************
	[{
		message : "CSRF token validation failed",
		response : {
			headers : {
				"Content-Type" : "text/plain;charset=utf-8",
				"x-csrf-token" : "Required"
			},
			responseText : "CSRF token validation failed",
			status : 403,
			statusText : "Forbidden"
		}
	}, {
		message : "message: 401 Unauthorized",
		response : {
			headers : {
				"Content-Type" : "text/html;charset=utf-8"
			},
			responseText : "<html>...</html>",
			status : 401,
			statusText : "Unauthorized"
		}
	}, {
		// OData V4 error response body as JSON
		// "The error response MUST be a single JSON object. This object MUST have a
		// single name/value pair named error. The value must be a JSON object."
		body : {
			error : {
				code : "/IWBEP/CM_V4_RUNTIME/021",
				message :
					// Note: "a human-readable, language-dependent representation of the error"
					"The state of the resource (entity) was already changed (If-Match)",
				"@Common.ExceptionCategory" : "Client_Error",
				"@Common.Application" : {
					ComponentId : "OPU-BSE-BEP",
					ServiceRepository : "DEFAULT",
					ServiceId : "/IWBEP/TEA_BUSI",
					ServiceVersion : "0001"
				},
				"@Common.TransactionId" : "5617D1F235DE73F0E10000000A60180C",
				"@Common.Timestamp" : "20151009142600.103179",
				"@Common.ErrorResolution" : {
					Analysis : "Run transaction /IWFND/ERROR_LOG [...]",
					Note : "See SAP Note 1797736 for error analysis "
						+ "(https://service.sap.com/sap/support/notes/1797736)"
				}
			}
		},
		isConcurrentModification : true,
		message : "The state of the resource (entity) was already changed (If-Match)",
		response : {
			headers : {
				"Content-Type" : "application/json; odata.metadata=minimal;charset=utf-8"
			},
			// "responseText" : JSON.stringify(this.body)
			status : 412,
			statusText : "Precondition Failed"
		}
	}, {
		strictHandlingFailed : true,
		message : "message: 412 Precondition Failed",
		response : {
			headers : {
				// https://datatracker.ietf.org/doc/html/rfc7240#section-3
				// ABNF: "Preference-Applied" ":" token [ BWS "=" BWS word ]
				"Preference-Applied" : "handling\t=  strict"
			},
			status : 412,
			statusText : "Precondition Failed"
		}
	}, {
		message : "message: 999 Invalid JSON",
		response : {
			headers : {
				"Content-Type" : "application/json"
			},
			responseText : "<html>...</html>",
			status : 999,
			statusText : "Invalid JSON"
		},
		warning : sinon.match(/SyntaxError/)
	}, {
		message : "message: 403 Forbidden",
		response : {
			headers : {
				"Content-Type" : "text/plain-not-quite-right"
			},
			status : 403,
			statusText : "Forbidden",
			responseText : "ignore this!"
		}
	}, {
		message : "Network error",
		response : {
			headers : {},
			status : 0,
			statusText : "error"
		}
	}, {
		message : "message: 404 Not Found",
		response : {
			headers : {},
			status : 404,
			statusText : "Not Found"
		}
	}, {
		// V2 error
		body : {
			error : {
				code : "0050569259751EE4BA9710043F8A5115",
				message : {
					lang : "en",
					value : "An unknown internal server error occurred"
				}
			}
		},
		message : "An unknown internal server error occurred",
		response : {
			headers : {
				"Content-Type" : "application/json;charset=UTF-8"
			},
			status : 500,
			statusText : "Internal Server Error"
		}
	}, {
		// no need to use UI5Date.getInstance as only the timestamp is relevant
		retryAfter : new Date(1234567890),
		message : "message: 503 Service Unavailable",
		response : {
			headers : {
				"Retry-After" : "0"
			},
			status : 503,
			statusText : "Service Unavailable"
		}
	}, {
		// no need to use UI5Date.getInstance as only the timestamp is relevant
		retryAfter : new Date(1234567890 + 42 * 1000),
		message : "message: 503 Service Unavailable",
		response : {
			headers : {
				"Retry-After" : "42"
			},
			status : 503,
			statusText : "Service Unavailable"
		}
	}, {
		// no need to use UI5Date.getInstance as only the timestamp is relevant
		retryAfter : new Date("Fri, 16 Jul 2021 14:04:39 GMT"),
		message : "message: 503 Service Unavailable",
		response : {
			headers : {
				"Retry-After" : "Fri, 16 Jul 2021 14:04:39 GMT"
			},
			status : 503,
			statusText : "Service Unavailable"
		}
	}].forEach(function (oFixture) {
		QUnit.test("createError: " + oFixture.message, function (assert) {
			var oError,
				jqXHR = {
					getResponseHeader : function (sName) {
						return oFixture.response.headers[sName];
					},
					status : oFixture.response.status,
					statusText : oFixture.response.statusText,
					responseText : oFixture.response.responseText || JSON.stringify(oFixture.body)
				};

			if (oFixture.retryAfter) {
				this.mock(Date).expects("now").atLeast(0).withExactArgs().returns(1234567890);
			}
			if (oFixture.warning) {
				this.oLogMock.expects("warning").withExactArgs(oFixture.warning,
					oFixture.response.responseText, "sap.ui.model.odata.v4.lib._Helper");
			}

			oError = _Helper.createError(jqXHR, "message", "/request/path", "original/path");

			assert.ok(oError instanceof Error);
			assert.deepEqual(oError.error, oFixture.body && oFixture.body.error);
			assert.strictEqual(oError.isConcurrentModification, oFixture.isConcurrentModification);
			assert.strictEqual(oError.strictHandlingFailed, oFixture.strictHandlingFailed);
			assert.strictEqual(oError.message, oFixture.message);
			assert.strictEqual(oError.status, oFixture.response.status);
			assert.strictEqual(oError.statusText, oFixture.response.statusText);
			assert.strictEqual(oError.requestUrl, "/request/path");
			assert.strictEqual(oError.resourcePath, "original/path");
			if (oFixture.retryAfter) {
				assert.strictEqual(oError.retryAfter.getTime(), oFixture.retryAfter.getTime());
			} else {
				assert.notOk("retryAfter" in oError);
			}
		});
	});

	//*********************************************************************************************
[
	{message : {/* any original message