function ClassWithCastBehavior(arg) {
					if ( !(this instanceof ClassWithCastBehavior) ) {
						return new ClassWithCastBehavior(arg);
					}
					this.value = arg;
				}
*************************************************
	// resource roots
	//****************************************************

	QUnit.module("register roots", {
		beforeEach: function() {
			var logSpy = this.logSpy = sinon.stub();
			this.listener = {
				onLogEntry: function(oLogEntry) {
					logSpy(oLogEntry.level, oLogEntry.message);
				}
			};
			Log.addLogListener(this.listener);
		},
		afterEach: function() {
			Log.removeLogListener(this.listener);
		}
	});

	QUnit.test("register w/o final flag (legacy variant)", function(assert) {

		var sPathInput = "/qunit/test/path";

		//first, set path to anything (should be overwritten then...)
		jQuery.sap.registerModulePath("qunit.test.path1", "/this/is/the/wrong/path/");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path1/))), "first path registration should have been logged");
		this.logSpy.resetHistory();

		jQuery.sap.registerModulePath("qunit.test.path1", sPathInput);
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path1/))), "second path registration should have been logged");
		this.logSpy.resetHistory();

		assert.equal(jQuery.sap.getModulePath("qunit.test.path1"), sPathInput, "non-final path has been overwritten");

	});

	QUnit.test("register with final=false", function(assert) {
		var sPathInput = "/qunit/test/path";

		//first, set path to anything (should be overwritten then...)
		jQuery.sap.registerModulePath("qunit.test.path2", "/this/is/the/wrong/path/");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path2/))), "first path registration should have been logged");
		this.logSpy.resetHistory();

		jQuery.sap.registerModulePath("qunit.test.path2", {'url': sPathInput, 'final': false});
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path2/))), "second path registration should have been logged");
		this.logSpy.resetHistory();

		assert.equal(jQuery.sap.getModulePath("qunit.test.path2"), sPathInput, "False final flag was handled successfully.");
	});

	QUnit.test("register with final=true", function(assert) {
		var sPathInput = "/qunit/test/path";

		//first, set path to the value it should be and stay (should NOT be overwritten then...)
		jQuery.sap.registerModulePath("qunit.test.path3", {'url': sPathInput, 'final': true});
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path3/)).and(sinon.match(/final/))), "first path registration should have been logged");
		this.logSpy.resetHistory();

		jQuery.sap.registerModulePath("qunit.test.path3", "/this/is/the/wrong/path/");
		assert.ok(this.logSpy.calledWith(Log.Level.WARNING, sinon.match(/registerResourcePath/).and(sinon.match(/already set as final/))), "warning should be logged when a final path is to be overwritten");
		this.logSpy.resetHistory();

		assert.equal(jQuery.sap.getModulePath("qunit.test.path3"), sPathInput, "Active final flag was handled successfully.");
	});

	QUnit.test("no empty Module URLs allowed", function(assert) {
		jQuery.sap.registerModulePath("qunit.test.path4", "");

		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path4/))), "first path registration should have been logged");
		this.logSpy.resetHistory();

		assert.equal(jQuery.sap.getModulePath("qunit.test.path4"), ".", "Setting empty URL avoided successfully.");
	});

	QUnit.test("removing URL registration", function(assert) {
		// remember URL without registration
		var sUrl = jQuery.sap.getResourcePath("qunit/test/path10/module.js");

		// register and check
		jQuery.sap.registerResourcePath("qunit/test/path10", "http://localhost/");
		assert.strictEqual(jQuery.sap.getResourcePath("qunit/test/path10/module.js"), "http://localhost/module.js", "returned URL should use the configured prefix");

		// deregister and check again
		jQuery.sap.registerResourcePath("qunit/test/path10", null);
		assert.notStrictEqual(jQuery.sap.getResourcePath("qunit/test/path10/module.js"), "http://localhost/module.js", "after deregistering prefix, returned URL should no longer use the configured prefix");
		assert.strictEqual(jQuery.sap.getResourcePath("qunit/test/path10/module.js"), sUrl, "returned URL should be the same as before");
	});

	QUnit.test("removing root registration", function(assert) {
		// remember URL without registration
		var sUrl = jQuery.sap.getResourcePath("x.js");

		// register different baseUrl
		jQuery.sap.registerResourcePath("", "foo/resources/");
		assert.notStrictEqual(jQuery.sap.getResourcePath("x.js"), sUrl, "returned URL should not be the same");

		// try to deregister baseUrl
		jQuery.sap.registerResourcePath("", null);
		assert.strictEqual(jQuery.sap.getResourcePath("x.js"), "./x.js", "returned URL should be the same as before the test");

	});

	QUnit.test("single log entry for redundant calls", function(assert) {
		jQuery.sap.registerModulePath("qunit.test.path8", "/qunit/test/path8");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/))), "first path registration should have been logged");
		this.logSpy.resetHistory();

		jQuery.sap.registerModulePath("qunit.test.path8", "/qunit/test/path8");
		assert.ok(this.logSpy.neverCalledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/))), "redundant call should not be logged");

		jQuery.sap.registerModulePath("qunit.test.path9", "/qunit/test/path9");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path9/))), "call with differing args should be logged");

		jQuery.sap.registerModulePath("qunit.test.path8", "/qunit/test/path8");
		assert.ok(this.logSpy.neverCalledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/))), "redundant call should not be logged, even after other calls");

		jQuery.sap.registerResourcePath("qunit/test/path8");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/)).and(sinon.match(/registration removed/))), "cleanup call should be logged");
		this.logSpy.resetHistory();

		jQuery.sap.registerResourcePath("qunit/test/path8");
		assert.ok(this.logSpy.neverCalledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/)).and(sinon.match(/registration removed/))), "redundant cleanup call should not be logged");

		jQuery.sap.registerModulePath("qunit.test.path8", "/qunit/test/path8");
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/))), "new call with same url should be logged after cleanup call");
		this.logSpy.resetHistory();

		jQuery.sap.registerModulePath("qunit.test.path8", { url: "/qunit/test/path8", "final": false });
		assert.ok(this.logSpy.neverCalledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/))), "redundant call should not be logged, even with different argument syntax");

		jQuery.sap.registerModulePath("qunit.test.path8", { url: "/qunit/test/path8", "final": true });
		assert.ok(this.logSpy.calledWith(Log.Level.INFO, sinon.match(/registerResourcePath/).and(sinon.match(/qunit\/test\/path8/)).and(sinon.match(/final/))), "call with same URL but different final flag should be logged");
	});

	QUnit.test("query parameters should be stripped off", function(assert) {
		var sExpected = "/qunit/test/path/with/query";
		jQuery.sap.registerModulePath("qunit.test.path5", sExpected + "?foo=bar&x=y");

		var sActual = jQuery.sap.getModulePath("qunit.test.path5");
		assert.equal(sActual, sExpected, "Query parameters should be stripped correctly.");
	});

	QUnit.test("hash should be stripped off", function(assert) {
		var sExpected = "/qunit/test/path/with/hash";
		jQuery.sap.registerModulePath("qunit.test.path6", sExpected + "#foo?bar=baz");

		var sActual = jQuery.sap.getModulePath("qunit.test.path6");
		assert.equal(sActual, sExpected, "Hash should be stripped correctly.");
	});

	QUnit.test("query parameters + hash should be stripped off", function(assert) {
		var sExpected = "/qunit/test/path/with/query/and/hash";
		jQuery.sap.registerModulePath("qunit.test.path7", sExpected + "?foo=bar&x=y#foo?bar=baz");

		var sActual = jQuery.sap.getModulePath("qunit.test.path7");
		assert.equal(sActual, sExpected, "Query parameters + hash should be stripped correctly.");
	});

	QUnit.test("getModulePath", function(assert) {
		jQuery.sap.registerModulePath("", "resources/");
		assert.equal(jQuery.sap.getModulePath("sap.ui.Global", ".js"), "resources/sap/ui/Global.js", "standard case 'sap.ui.Global'");
		assert.equal(jQuery.sap.getModulePath("jquery.sap.xml", ".js"), "resources/jquery.sap.xml.js", "special case 'jquery.sap.xml'");
		assert.equal(jQuery.sap.getModulePath("sap.ui.core", "/"), "resources/sap/ui/core/", "folder case");
		assert.equal(jQuery.sap.getModulePath("sap.ui.core", ""), "resources/sap/ui/core", "no suffix");

		jQuery.sap.registerModulePath("sap.ui.Global", "resources/Global/");
		assert.equal(jQuery.sap.getModulePath("sap.ui.Global", ".js"), "resources/Global.js", "special case base name mapping");
		jQuery.sap.registerModulePath("sap.ui.Global", "resources/sap/ui/Global/");

	});

	QUnit.test("getResourcePath", function(assert) {

		jQuery.sap.registerResourcePath("", "resources/");
		assert.equal(jQuery.sap.getResourcePath("sap/ui/Global.js"), "resources/sap/ui/Global.js", "standard case with extension .js: 'sap/ui/Global.js'");
		assert.equal(jQuery.sap.getResourcePath("sap/ui/Global.view.js"), "resources/sap/ui/Global.view.js", "standard case with extension .view.js: 'sap/ui/Global.view.js'");
		assert.strictEqual(jQuery.sap.getResourcePath("sap/ui/core/util/"), "resources/sap/ui/core/util", "packages resolve to a path without a trailing slash");
		assert.strictEqual(jQuery.sap.getResourcePath(""), "resources", "root package resolves to base URL without a trailing slash");

		jQuery.sap.registerResourcePath("sap/ui/Global", "resources/Global");
		assert.equal(jQuery.sap.getResourcePath("sap/ui/Global", ".js"), "resources/Global.js", "special case: mapping of the base name");
		jQuery.sap.registerResourcePath("sap/ui/Global");

		jQuery.sap.registerResourcePath("sap.ext", "resources/some/");
		assert.equal(jQuery.sap.getResourcePath("sap.ext/Global", ".js"), "resources/some/Global.js", "special case folder with dots in folder and single name");
		jQuery.sap.registerResourcePath("sap.ext", "resources/sap.ext/");

		jQuery.sap.registerResourcePath("sap/ui.ext", "resources/some/");
		assert.equal(jQuery.sap.getResourcePath("sap/ui.ext/Global", ".js"), "resources/some/Global.js", "special case: mapping with dots in folder");
		assert.equal(jQuery.sap.getResourcePath("sap/ui.ext.js"), "resources/some.js", "special case: base name mapping with dots in folder");
		assert.equal(jQuery.sap.getResourcePath("sap/ui.ext.view.js"), "resources/some.view.js", "special case: base name mapping with dots in folder and complex extension");
		assert.equal(jQuery.sap.getResourcePath("sap/ui.ext", ".js"), "resources/some.js", "special case base name mapping with dots in folder");
		jQuery.sap.registerResourcePath("sap/ui.ext");

	});

	QUnit.test("toUrl", function(assert) {
		var done = assert.async();

		jQuery.sap.registerResourcePath("", "resources/");

		// toURL special cases
		assert.throws(
			function() {
				sap.ui.require.toUrl('/sap/test');
			},
			Error("The provided argument '/sap/test' may not start with a slash"),
			"absolute path is not supported"
		);
		assert.equal(sap.ui.require.toUrl('sap/test'), "resources/sap/test", "toUrl should support standard path");
		assert.equal(sap.ui.require.toUrl('sap/test/'), "resources/sap/test/", "toUrl leaves trailing slash character intact");
		assert.equal(sap.ui.require.toUrl('sap/test/.library'), "resources/sap/test/.library", "toUrl supports files which start with a dot character");
		assert.equal(sap.ui.require.toUrl('sap/test/..library'), "resources/sap/test/..library", "toUrl supports files which start with two dot character");
		assert.equal(sap.ui.require.toUrl('sap/test/./library'), "resources/sap/test/library", "toUrl supports paths which contain relative segments");
		assert.equal(sap.ui.require.toUrl('sap/test/./library/'), "resources/sap/test/library/", "toUrl supports paths which contain relative segments and trailing slash character");
		assert.equal(sap.ui.require.toUrl('sap/test/./.library'), "resources/sap/test/.library", "toUrl supports paths which contain relative segments and filename starting with dot character");
		assert.equal(sap.ui.require.toUrl('sap/test/../.library'), "resources/sap/.library", "toUrl supports paths which contain relative segments with parent path and filename starting with dot character");
		assert.equal(sap.ui.require.toUrl('sap/test/../library'), "resources/sap/library", "toUrl supports paths which contain relative segments with parent path");
		assert.equal(sap.ui.require.toUrl('sap/test/.././test/./library'), "resources/sap/test/library", "toUrl supports paths which contain relative segments");

		/* relative names are not supported for the root
		assert.equal(sap.ui.require.toUrl('/../.library'), "resources/sap/.library", "toUrl should leave trailing slash intact");
		assert.equal(sap.ui.require.toUrl('../.library'), "resources/sap/.library", "toUrl should leave trailing slash intact");
		assert.equal(sap.ui.require.toUrl('./.library'), "resources/sap/.library", "toUrl should leave trailing slash intact");
		assert.equal(sap.ui.require.toUrl('/./.library'), "resources/sap/.library", "toUrl should leave trailing slash intact");