public static void GetMatchNonMatchTest(
			string headerName, 
			string[] values, 
			bool existsInStore,
			bool expectReturnNull,
			HttpStatusCode expectedStatus = HttpStatusCode.Unused)
		{
			// setup 
			var mocks = new MockRepository();
			var entityTagStore = mocks.StrictMock<IEntityTagStore>();
			var entityTagHandler = new CachingHandler(entityTagStore);
			var request = new HttpRequestMessage(HttpMethod.Get, TestUrl);
			request.Headers.Add(headerName, values);
			TimedEntityTagHeaderValue entityTagHeaderValue = new TimedEntityTagHeaderValue("\"12345678\"");

			if(values.Length>0) // if 
				entityTagStore.Expect(x => x.TryGetValue(Arg<EntityTagKey>.Matches(etg => etg.ResourceUri == entityTagHandler.UriTrimmer(new Uri(TestUrl))),
					out Arg<TimedEntityTagHeaderValue>.Out(entityTagHeaderValue).Dummy)).Return(existsInStore);

			mocks.ReplayAll();


			// run 
			var matchNoneMatch = entityTagHandler.GetIfMatchNoneMatch();
			// verify 
			Task<HttpResponseMessage> resultTask = matchNoneMatch(request);
			Assert.That(expectReturnNull ^ resultTask != null, "result was not as expected");
			if(resultTask!=null && expectedStatus != HttpStatusCode.Unused)
			{
				Assert.AreEqual(expectedStatus, resultTask.Result.StatusCode, "Status code");				
			}
			mocks.VerifyAll();
		}
        public static void TestCachingContinuation(
			string method,
			bool existsInStore,
			bool addVaryHeader,
			bool addLastModifiedHeader,
			bool alreadyHasLastModified,
			string[] varyByHeader)
        {
            // setup
            var mocks = new MockRepository();
            var request = new HttpRequestMessage(new HttpMethod(method), TestUrl);
            request.Headers.Add(HttpHeaderNames.Accept, "text/xml");
            request.Headers.Add(HttpHeaderNames.AcceptLanguage, "en-GB");
            var entityTagStore = mocks.StrictMock<IEntityTagStore>();
            var cachingHandler = new CachingHandler(entityTagStore, varyByHeader)
                                 	{
                                 		AddLastModifiedHeader = addLastModifiedHeader,
                                        AddVaryHeader = addVaryHeader
                                 	};

            var entityTagHeaderValue = new TimedEntityTagHeaderValue("\"12345678\"");
            var entityTagKey = new EntityTagKey(TestUrl, new string[0]);
            cachingHandler.EntityTagKeyGenerator = (x, y) => entityTagKey;
            cachingHandler.ETagValueGenerator = (x, y) => new EntityTagHeaderValue(entityTagHeaderValue.Tag);
            entityTagStore.Expect(x => x.TryGet(Arg<EntityTagKey>.Matches(etg => etg.ResourceUri == TestUrl),
                out Arg<TimedEntityTagHeaderValue>.Out(entityTagHeaderValue).Dummy)).Return(existsInStore);

            if (!existsInStore  || request.Method == HttpMethod.Put || request.Method == HttpMethod.Post)
            {
                entityTagStore.Expect(
                    x => x.AddOrUpdate(Arg<EntityTagKey>.Matches(etk => etk == entityTagKey),
                        Arg<TimedEntityTagHeaderValue>.Matches(ethv => ethv.Tag == entityTagHeaderValue.Tag)));
            }

            mocks.ReplayAll();

            var response = new HttpResponseMessage();
            response.Content = new ByteArrayContent(new byte[0]);
            if(alreadyHasLastModified)
                response.Content.Headers.Add(HttpHeaderNames.LastModified, DateTimeOffset.Now.ToString("r"));

            var cachingContinuation = cachingHandler.GetCachingContinuation(request);
            var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
            taskCompletionSource.SetResult(response);

            // run
            var httpResponseMessage = cachingContinuation(taskCompletionSource.Task);

            // test
            if(addLastModifiedHeader)
            {
                Assert.That(httpResponseMessage.Content.Headers.Any(x=>x.Key == HttpHeaderNames.LastModified),
                    "LastModified does not exist");
            }
            if(!addLastModifiedHeader && !alreadyHasLastModified)
            {
                Assert.That(!httpResponseMessage.Content.Headers.Any(x => x.Key == HttpHeaderNames.LastModified),
                    "LastModified exists");
            }
        }
		public static void TestCacheInvalidationForPost(string method)
		{
			// setup
			var locationUrl = new Uri("http://api/SomeLocationUrl");
			var mocks = new MockRepository();
			var request = new HttpRequestMessage(new HttpMethod(method), TestUrl);
			string routePattern = "http://myserver/api/stuffs/*";
			var entityTagStore = mocks.StrictMock<IEntityTagStore>();
			var linkedUrls = new[] { "url1", "url2" };
			var cachingHandler = new CachingHandler(entityTagStore)
			{
				LinkedRoutePatternProvider = (url, mthd) => linkedUrls
			};
			var entityTagKey = new EntityTagKey(TestUrl, new string[0], routePattern);
			var response = new HttpResponseMessage();
			response.Headers.Location = locationUrl;
			var invalidateCacheForPost = cachingHandler.PostInvalidationRule(entityTagKey, request, response);
			if(method == "POST")
			{
				entityTagStore.Expect(x => x.RemoveAllByRoutePattern(locationUrl.ToString())).Return(1);				
			}
			mocks.ReplayAll();

			// run
			invalidateCacheForPost();

			// verify
			mocks.VerifyAll();

			
		}
		public static void TestCacheInvalidation(string method)
		{
			// setup
			var mocks = new MockRepository();
			var request = new HttpRequestMessage(new HttpMethod(method), TestUrl);
			string routePattern = "http://myserver/api/stuffs/*";
			var entityTagStore = mocks.StrictMock<IEntityTagStore>();
			var linkedUrls = new []{"url1", "url2"};
			var cachingHandler = new CachingHandler(entityTagStore)
			                     	{
										LinkedRoutePatternProvider = (url, mthd) => linkedUrls
			                     	};
			var entityTagKey = new EntityTagKey(TestUrl, new string[0], routePattern);
			var response = new HttpResponseMessage();
			var invalidateCache = cachingHandler.InvalidateCache(entityTagKey, request, response);
			entityTagStore.Expect(x => x.RemoveAllByRoutePattern(routePattern)).Return(1);
			entityTagStore.Expect(x => x.RemoveAllByRoutePattern(linkedUrls[0])).Return(0);
			entityTagStore.Expect(x => x.RemoveAllByRoutePattern(linkedUrls[1])).Return(0);
			mocks.ReplayAll();

			// run
			invalidateCache();

			// verify
			mocks.VerifyAll();


		}
		public static void TestGetReturnsNullIfVerbNotGet()
		{
			// setup
			var request = new HttpRequestMessage(HttpMethod.Put, TestUrl);
			var entityTagHandler = new CachingHandler();
			var getRule = entityTagHandler.GetIfMatchNoneMatch();
			
			// run
			var task = getRule(request);

			// verify
			Assert.IsNull(task);
		}
		public static void TestGetReturnsBadRequestIfBothIfMatchAndIfNoneMatchExist()
		{
			// setup
			var request = new HttpRequestMessage(HttpMethod.Get, TestUrl);
			request.Headers.Add(HttpHeaderNames.IfMatch, "\"123\"");
			request.Headers.Add(HttpHeaderNames.IfNoneMatch, "\"123\"");
			var entityTagHandler = new CachingHandler();
			var getRule = entityTagHandler.GetIfMatchNoneMatch();

			// run
			var task = getRule(request);
			var httpResponseMessage = task.Result;

			// verify
			Assert.AreEqual(HttpStatusCode.BadRequest, httpResponseMessage.StatusCode);
		}
        public static void GetModifiedNotModifiedTest(
				string headerName,
				bool resourceHasChanged,
				bool expectReturnNull,
				HttpStatusCode expectedStatus = HttpStatusCode.Unused)
        {
            // setup
            var mocks = new MockRepository();
            var entityTagStore = mocks.StrictMock<IEntityTagStore>();
            var entityTagHandler = new CachingHandler(entityTagStore);
            var request = new HttpRequestMessage(HttpMethod.Get, TestUrl);
            DateTimeOffset lastChanged = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(7));
            DateTimeOffset lastModifiedInQuestion = resourceHasChanged
                                                        ? lastChanged.Subtract(TimeSpan.FromDays(1))
                                                        : lastChanged.Add(TimeSpan.FromDays(1));

            request.Headers.Add(headerName, lastModifiedInQuestion.ToString("r"));
            var entityTagHeaderValue = new TimedEntityTagHeaderValue("\"12345678\"")
                {LastModified = lastChanged};

            entityTagStore.Expect(x => x.TryGet(Arg<EntityTagKey>.Matches(etg => etg.ResourceUri == TestUrl),
                out Arg<TimedEntityTagHeaderValue>.Out(entityTagHeaderValue).Dummy)).Return(true);

            mocks.ReplayAll();

            // run
            var modifiedUnmodifiedSince = entityTagHandler.GetIfModifiedUnmodifiedSince();
            var task = modifiedUnmodifiedSince(request);
            HttpResponseMessage response = task == null ? null : task.Result;

            // verify
            Assert.That(expectReturnNull ^ task != null, "result was not as expected");
            if (task != null && expectedStatus != HttpStatusCode.Unused)
            {
                Assert.AreEqual(expectedStatus, response.StatusCode, "Status code");
            }
            mocks.VerifyAll();
        }
		public static void TestPutIfUnmodifiedReturnsNullIfVerbNotPut()
		{
			// setup
			var request = new HttpRequestMessage(HttpMethod.Get, TestUrl);
			var entityTagHandler = new CachingHandler();
			var getRule = entityTagHandler.PutIfUnmodifiedSince();
			// run
			var task = getRule(request);

			// verify
			Assert.IsNull(task);
		}
		public static void TestGetReturnsBadRequestIfBothIfModifiedAndIfUnmodifiedExist()
		{
			// setup
			var request = new HttpRequestMessage(HttpMethod.Get, TestUrl);
			request.Headers.Add(HttpHeaderNames.IfModifiedSince, DateTimeOffset.Now.ToString("r"));
			request.Headers.Add(HttpHeaderNames.IfUnmodifiedSince, DateTimeOffset.Now.ToString("r"));
			var entityTagHandler = new CachingHandler();
			var getRule = entityTagHandler.GetIfModifiedUnmodifiedSince();

			// run
			var task = getRule(request);
			var httpResponseMessage = task.Result;

			// verify
			Assert.AreEqual(HttpStatusCode.BadRequest, httpResponseMessage.StatusCode);
		}
		public static void AddCaching(string method,
			bool existsInStore,
			bool addVaryHeader,
			bool addLastModifiedHeader,
			bool alreadyHasLastModified,
			string[] varyByHeader)
		{
			// setup 
			var mocks = new MockRepository();
			var request = new HttpRequestMessage(new HttpMethod(method), TestUrl);
			request.Headers.Add(HttpHeaderNames.Accept, "text/xml");
			request.Headers.Add(HttpHeaderNames.AcceptLanguage, "en-GB");
			var entityTagStore = mocks.StrictMock<IEntityTagStore>();
			var entityTagHeaderValue = new TimedEntityTagHeaderValue("\"12345678\"");
			var cachingHandler = new CachingHandler(entityTagStore, varyByHeader)
			{
				AddLastModifiedHeader = addLastModifiedHeader,
				AddVaryHeader = addVaryHeader,
				ETagValueGenerator = (x,y) => entityTagHeaderValue
			};

			
			var entityTagKey = new EntityTagKey(TestUrl, new[] {"text/xml", "en-GB"}, TestUrl + "/*");

			entityTagStore.Expect(x => x.TryGetValue(Arg<EntityTagKey>.Matches(etg => etg.ResourceUri == TestUrl),
				out Arg<TimedEntityTagHeaderValue>.Out(entityTagHeaderValue).Dummy)).Return(existsInStore);

			if (!existsInStore)
			{
				entityTagStore.Expect(
					x => x.AddOrUpdate(Arg<EntityTagKey>.Matches(etk => etk == entityTagKey),
						Arg<TimedEntityTagHeaderValue>.Matches(ethv => ethv.Tag == entityTagHeaderValue.Tag)));
			}

			var response = new HttpResponseMessage();
			response.Content = new ByteArrayContent(new byte[0]);
			if (alreadyHasLastModified)
				response.Content.Headers.Add(HttpHeaderNames.LastModified, DateTimeOffset.Now.ToString("r"));

			var cachingContinuation = cachingHandler.AddCaching(entityTagKey, request, response, request.Headers);
			mocks.ReplayAll();

			// run
			cachingContinuation();

			// verify

			// test kast modified only if it is GET and PUT
			if (addLastModifiedHeader && method.IsIn("PUT", "GET"))
			{
				Assert.That(response.Content.Headers.Any(x => x.Key == HttpHeaderNames.LastModified),
					"LastModified does not exist");
			}
			if (!addLastModifiedHeader && !alreadyHasLastModified)
			{
				Assert.That(!response.Content.Headers.Any(x => x.Key == HttpHeaderNames.LastModified),
					"LastModified exists");
			}
			mocks.VerifyAll();

		}