{
	"getStateByUri": [
		{
			"name": "should return null if URI is not routed",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/none/val1/val2?a=val3&b=val4",
			"expectedState": null
		},
		{
			"name": "should return null if URI is not a string",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": null,
			"expectedState": null
		},
		{
			"name": "should return null if URI is an empty string",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "",
			"expectedState": null
		},
		{
			"name": "should return null if there are not routes",
			"routes": [],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": null
		},
		{
			"name": "should return null if route is empty",
			"routes": [
				"",
				""
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": null
		},
		{
			"name": "should return the correct state for correct URI",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the correct state for correct URI if the route is an object",
			"routes": [{
				"expression": "/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			}],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the correct state for correct URI and store names which contains slash",
			"routes": [
				"/state/:arg1[group1/Store1, group2/Store2]/:arg2[group2/Store2]?a=:arg3[group1/Store1]&b=:arg4[group3/Store3]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"group1/Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"group2/Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"group3/Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the correct state for correct URI and store names which contains dashes",
			"routes": [
				"/state/:arg1[group-1/Store1, group-2/Store2]/:arg2[group-2/Store2]?a=:arg3[group-1/Store1]&b=:arg4[group-3/Store3]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"group-1/Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"group-2/Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"group-3/Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the state if one query string parameter is not specified",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the state if query string parameters are not specified",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should return the state if query string has wrong parameters",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?c=val3&d=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should return the state if it has routes with the same paths but the second has no query",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]",
				"/state/:arg1[Store1, Store2]/:arg2[Store2]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should return the state if it has routes with the same paths but the second has query",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]",
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the state if it query parameter is an array",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4&a=val5&a=val6",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": ["val3","val5","val6"]
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return the state if route has wrong query parameters",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=b&b=c"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should return the state if route has array query parameters",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]&a=:arg5[Store1]&a=:arg6[Store1]"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should return a proper state if actual parameters contain dots in their names",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?q.a=:arg3[Store1]&q.b=:arg4[Store3]"
			],
			"uri": "/state/va.l1/va.l2?q.a=va.l3&q.b=va.l4",
			"expectedState": {
				"Store1": {
					"arg1": "va.l1",
					"arg3": "va.l3"
				},
				"Store2": {
					"arg1": "va.l1",
					"arg2": "va.l2"
				},
				"Store3": {
					"arg4": "va.l4"
				}
			}
		},
		{
			"name": "should support another order of query parameters",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?b=val4&a=val3",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should support when query parameters are empty",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should support when query parameter is empty",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg2[Store2]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?a=&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": ""
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should support when static path without parameters",
			"routes": [
				"/state?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg3": "val3"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should support collecting several values into the list",
			"routes": [
				"/state/:arg1[Store1, Store2]/:arg3[Store1]?a=:arg3[Store1]&b=:arg4[Store3]"
			],
			"uri": "/state/val1/val2?a=valX&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": [
						"val2",
						"valX"
					]
				},
				"Store2": {
					"arg1": "val1"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should support partial parameters",
			"routes": [
				"/state/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
			],
			"uri": "/state/wval1q/qval2s?a=aval3z&b=xval4y",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "val3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "val4"
				}
			}
		},
		{
			"name": "should support parameters with %26 and %3D substrings",
			"routes": [
				"/state/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=:arg3[Store1]z&b=:arg4[Store3]y"
			],
			"uri": "/state/wval1q/qval2s?a=%3Dval%263z&b=%3Dval%264y",
			"expectedState": {
				"Store1": {
					"arg1": "val1",
					"arg3": "=val&3"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				},
				"Store3": {
					"arg4": "=val&4"
				}
			}
		},
		{
			"name": "should support partial parameters and the empty value",
			"routes": [
				"/state:noop/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
			],
			"uri": "/state/wq/qs?a=az&b=xy",
			"expectedState": {
				"Store1": {
					"arg1": "",
					"arg3": ""
				},
				"Store2": {
					"arg1": "",
					"arg2": ""
				},
				"Store3": {
					"arg4": ""
				}
			}
		},
		{
			"name": "should support partial parameters and set them empty if they are absent in query",
			"routes": [
				"/state/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
			],
			"uri": "/state/wval1q/qval2s?a=val3&b=val4",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg1": "val1",
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should support parameters without values in query",
			"routes": [
				"/state?a:arg1[Store1]&b:arg2[Store2]=x:arg3[Store3]&b=some"
			],
			"uri": "/state?aval1&bval2",
			"expectedState": {
				"Store1": {
					"arg1": "val1"
				},
				"Store2": {
					"arg2": "val2"
				}
			}
		},
		{
			"name": "should return null if partial parameters are absent in path",
			"routes": [
				"/state/w:arg1[Store1, Store2]q/q:arg2[Store2]s?a=a:arg3[Store1]z&b=x:arg4[Store3]y"
			],
			"uri": "/state/val1/val2?a=val3&b=val4",
			"expectedState": null
		}
	],
	"getRouteURI": [
		{
			"name": "should throw an error when there is no such route",
			"routes": [
				{
					"name": "test",
					"expression": "/:section[Store1, Store2]/:subsection[Store2]"
				}
			],
			"arguments": {
				"name": "wrong",
				"parameters": {
					"section": "test-section",
					"subsection": "test-subsection"
				}
			},
			"expectedError": "There is no such route called \"wrong\""
		},
		{
			"name": "should throw an error when a path parameter has an array value",
			"routes": [
				{
					"name": "test",
					"expression": "/:section[Store1, Store2]/:subsection[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"section": ["test-section"],
					"subsection": "test-subsection"
				}
			},
			"expectedError": "Array value is not supported for the parameter \"section\""
		},
		{
			"name": "should throw an error when a quern name parameter has an array value",
			"routes": [
				{
					"name": "test",
					"expression": "/some?:qParam1[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"qParam1": ["test-section"]
				}
			},
			"expectedError": "Array value is not supported for the parameter \"qParam1\""
		},
		{
			"name": "should paste an empty string when there is no parameter in the path",
			"routes": [
				{
					"name": "test",
					"expression": "/:section[Store1, Store2]/:subsection[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"subsection": "test-subsection"
				}
			},
			"expectedURI": "//test-subsection"
		},
		{
			"name": "should return URI for path parameters",
			"routes": [
				{
					"name": "test",
					"expression": "/:section[Store1, Store2]/:subsection[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"section": "test-section",
					"subsection": "test-subsection"
				}
			},
			"expectedURI": "/test-section/test-subsection"
		},
		{
			"name": "should encode path parameters",
			"routes": [
				{
					"name": "test",
					"expression": "/:section[Store1, Store2]/:subsection[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"section": "test/section",
					"subsection": "test/subsection"
				}
			},
			"expectedURI": "/test%2Fsection/test%2Fsubsection"
		},
		{
			"name": "should return URI for path and query parameters",
			"routes": [
				{
					"name": "test",
					"expression": "/:param1[Store1, Store2]/:param2[Store2]?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"param1": "value1",
					"param2": "value2",
					"qParam1": "qValue1",
					"qParam2": "qValue2",
					"qParam3": "qValue3"
				}
			},
			"expectedURI": "/value1/value2?qValue1=value&query=qValue2&qValue3"
		},
		{
			"name": "should return URI for path and query parameters surrounded by text",
			"routes": [
				{
					"name": "test",
					"expression": "/pa:param1[Store1]th1/pa:param2[Store2]th2?que:qParam1[Store2]ry1=value&query=va:qParam2[Store2]lue1&que:qParam3[Store3]ry2&que:qParam4[Store4]ry3=val:qParam5[Store5]ue2"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"param1": "!value1!",
					"param2": "!value2!",
					"qParam1": "!qValue1!",
					"qParam2": "!qValue2!",
					"qParam3": "!qValue3!",
					"qParam4": "!qValue4!",
					"qParam5": ["!qValue5-1!", "!qValue5-2!", "!qValue5-3!"]
				}
			},
			"expectedURI": "/pa!value1!th1/pa!value2!th2?que!qValue1!ry1=value&query=va!qValue2!lue1&que!qValue3!ry2&que!qValue4!ry3=val!qValue5-1!ue2&que!qValue4!ry3=val!qValue5-2!ue2&que!qValue4!ry3=val!qValue5-3!ue2"
		},
		{
			"name": "should return URI for path and query parameters with array values",
			"routes": [
				{
					"name": "test",
					"expression": "/some?:qParam1[Store2]=:qParam2[Store2]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"qParam1": "qValue1",
					"qParam2": ["qValue2-1", "qValue2-2", "qValue2-3"]
				}
			},
			"expectedURI": "/some?qValue1=qValue2-1&qValue1=qValue2-2&qValue1=qValue2-3"
		},
		{
			"name": "should return URI for path and optional query parameters",
			"routes": [
				{
					"name": "test",
					"expression": "/:param1[Store1, Store2]/:param2[Store2]?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {
					"param1": "value1",
					"param2": "value2",
					"qParam2": "qValue2"
				}
			},
			"expectedURI": "/value1/value2?query=qValue2"
		},
		{
			"name": "should return URI without query string if parameters=undefined for optional parameters",
			"routes": [
				{
					"name": "test",
					"expression": "/some?:qParam1[Store2]=value&query=:qParam2[Store2]&:qParam3[Store3]"
				}
			],
			"arguments": {
				"name": "test"
			},
			"expectedURI": "/some"
		},
		{
			"name": "should return URI without query parameter if the value was not specified",
			"routes": [
				{
					"name": "test",
					"expression": "/some?qParam=:qValue[Store]"
				}
			],
			"arguments": {
				"name": "test",
				"parameters": {}
			},
			"expectedURI": "/some"
		}
	]
}
