diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonPatchTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonPatchTest.cs index ac442f15ff..52184433a2 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonPatchTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonPatchTest.cs @@ -22,15 +22,17 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests private readonly Action _configureServices = new Startup().ConfigureServices; [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] - public async Task JsonPatch_ValidAddOperation_List(string url) + public async Task JsonPatch_ValidAddOperation_Success(string url) { // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var client = server.CreateClient(); - var input = "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", " + + var input = "[{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/2\", " + "\"value\": { \"OrderName\": \"Name2\" }}]"; var request = new HttpRequestMessage { @@ -49,6 +51,123 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests } [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] + public async Task JsonPatch_ValidReplaceOperation_Success(string url) + { + // Arrange + var server = TestHelper.CreateServer(_app, SiteName, _configureServices); + var client = server.CreateClient(); + + var input = "[{ \"op\": \"replace\", " + + "\"path\": \"Customer/Orders/0/OrderName\", " + + "\"value\": \"ReplacedOrder\" }]"; + var request = new HttpRequestMessage + { + Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"), + Method = new HttpMethod("PATCH"), + RequestUri = new Uri(url) + }; + + // Act + var response = await client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + var customer = JsonConvert.DeserializeObject(body); + Assert.Equal("ReplacedOrder", customer.Orders[0].OrderName); + } + + [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] + public async Task JsonPatch_ValidCopyOperation_Success(string url) + { + // Arrange + var server = TestHelper.CreateServer(_app, SiteName, _configureServices); + var client = server.CreateClient(); + + var input = "[{ \"op\": \"copy\", " + + "\"path\": \"Customer/Orders/1/OrderName\", " + + "\"from\": \"Customer/Orders/0/OrderName\"}]"; + var request = new HttpRequestMessage + { + Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"), + Method = new HttpMethod("PATCH"), + RequestUri = new Uri(url) + }; + + // Act + var response = await client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + var customer = JsonConvert.DeserializeObject(body); + Assert.Equal("Order0", customer.Orders[1].OrderName); + } + + [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] + public async Task JsonPatch_ValidMoveOperation_Success(string url) + { + // Arrange + var server = TestHelper.CreateServer(_app, SiteName, _configureServices); + var client = server.CreateClient(); + + var input = "[{ \"op\": \"move\", " + + "\"path\": \"Customer/Orders/1/OrderName\", " + + "\"from\": \"Customer/Orders/0/OrderName\"}]"; + var request = new HttpRequestMessage + { + Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"), + Method = new HttpMethod("PATCH"), + RequestUri = new Uri(url) + }; + + // Act + var response = await client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + var customer = JsonConvert.DeserializeObject(body); + Assert.Equal("Order0", customer.Orders[1].OrderName); + Assert.Null(customer.Orders[0].OrderName); + } + + [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] + [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] + public async Task JsonPatch_ValidRemoveOperation_Success(string url) + { + // Arrange + var server = TestHelper.CreateServer(_app, SiteName, _configureServices); + var client = server.CreateClient(); + + var input = "[{ \"op\": \"remove\", " + + "\"path\": \"Customer/Orders/1/OrderName\"}]"; + var request = new HttpRequestMessage + { + Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"), + Method = new HttpMethod("PATCH"), + RequestUri = new Uri(url) + }; + + // Act + var response = await client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + var customer = JsonConvert.DeserializeObject(body); + Assert.Null(customer.Orders[1].OrderName); + } + + [Theory] + [InlineData("http://localhost/jsonpatch/JsonPatchWithoutModelState")] [InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")] [InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")] public async Task JsonPatch_MultipleValidOperations_Success(string url) @@ -57,9 +176,14 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var client = server.CreateClient(); - var input = "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", " + - "\"value\": { \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/2\", " + - "\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": \"Customer/Orders/2/OrderName\", " + + var input = "[{ \"op\": \"add\", "+ + "\"path\": \"Customer/Orders/2\", " + + "\"value\": { \"OrderName\": \"Name2\" }}, " + + "{\"op\": \"copy\", " + + "\"from\": \"Customer/Orders/2\", " + + "\"path\": \"Customer/Orders/3\" }, " + + "{\"op\": \"replace\", " + + "\"path\": \"Customer/Orders/2/OrderName\", " + "\"value\": \"ReplacedName\" }]"; var request = new HttpRequestMessage { @@ -86,33 +210,45 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests { new object[] { "http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch", - "[{ \"op\": \"add\", \"path\": \"Customer/Orders/5\", " + + "[{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/5\", " + "\"value\": { \"OrderName\": \"Name5\" }}]", "{\"Patch.Customer\":[\"For operation 'add' on array property at path " + "'Customer/Orders/5', the index is larger than the array size.\"]}" }, new object[] { "http://localhost/jsonpatch/JsonPatchWithModelState", - "[{ \"op\": \"add\", \"path\": \"Customer/Orders/5\", " + + "[{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/5\", " + "\"value\": { \"OrderName\": \"Name5\" }}]", "{\"Customer\":[\"For operation 'add' on array property at path " + "'Customer/Orders/5', the index is larger than the array size.\"]}" }, new object[] { "http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch", - "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", \"value\": " + - "{ \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/4\", " + - "\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": " + - "\"Customer/Orders/2/OrderName\", \"value\": \"ReplacedName\" }]", + "[{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/2\", " + + "\"value\": { \"OrderName\": \"Name2\" }}, " + + "{\"op\": \"copy\", " + + "\"from\": \"Customer/Orders/4\", " + + "\"path\": \"Customer/Orders/3\" }, " + + "{\"op\": \"replace\", " + + "\"path\": \"Customer/Orders/2/OrderName\", " + + "\"value\": \"ReplacedName\" }]", "{\"Patch.Customer\":[\"For operation 'copy' on array property at path " + "'Customer/Orders/4', the index is larger than the array size.\"]}" }, new object[] { "http://localhost/jsonpatch/JsonPatchWithModelState", - "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", \"value\": " + - "{ \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/4\", " + - "\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": " + - "\"Customer/Orders/2/OrderName\", \"value\": \"ReplacedName\" }]", + "[{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/2\", " + + "\"value\": { \"OrderName\": \"Name2\" }}, " + + "{\"op\": \"copy\", " + + "\"from\": \"Customer/Orders/4\", " + + "\"path\": \"Customer/Orders/3\" }, " + + "{\"op\": \"replace\", " + + "\"path\": \"Customer/Orders/2/OrderName\", " + + "\"value\": \"ReplacedName\" }]", "{\"Customer\":[\"For operation 'copy' on array property at path " + "'Customer/Orders/4', the index is larger than the array size.\"]}" } @@ -141,5 +277,30 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); Assert.Equal(errorMessage, body); } + + [Fact] + public async Task JsonPatch_InvalidData_FormatterErrorInModelState_Failure() + { + // Arrange + var server = TestHelper.CreateServer(_app, SiteName, _configureServices); + var client = server.CreateClient(); + + var input = "{ \"op\": \"add\", " + + "\"path\": \"Customer/Orders/2\", " + + "\"value\": { \"OrderName\": \"Name2\" }}"; + var request = new HttpRequestMessage + { + Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"), + Method = new HttpMethod("PATCH"), + RequestUri = new Uri("http://localhost/jsonpatch/JsonPatchWithModelState") + }; + + // Act + var response = await client.SendAsync(request); + + // Assert + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("{\"\":[\"The input was not valid.\"]}", body); + } } } \ No newline at end of file diff --git a/test/WebSites/JsonPatchWebSite/Controllers/JsonPatchController.cs b/test/WebSites/JsonPatchWebSite/Controllers/JsonPatchController.cs index d9f240a8d0..0e1c3346b5 100644 --- a/test/WebSites/JsonPatchWebSite/Controllers/JsonPatchController.cs +++ b/test/WebSites/JsonPatchWebSite/Controllers/JsonPatchController.cs @@ -14,16 +14,23 @@ namespace JsonPatchWebSite.Controllers [HttpPatch] public IActionResult JsonPatchWithModelState([FromBody] JsonPatchDocument patchDoc) { - var customer = CreateCustomer(); + if (patchDoc != null) + { + var customer = CreateCustomer(); - patchDoc.ApplyTo(customer, ModelState); + patchDoc.ApplyTo(customer, ModelState); - if (!ModelState.IsValid) + if (!ModelState.IsValid) + { + return HttpBadRequest(ModelState); + } + + return new ObjectResult(customer); + } + else { return HttpBadRequest(ModelState); } - - return new ObjectResult(customer); } [HttpPatch] @@ -43,6 +50,16 @@ namespace JsonPatchWebSite.Controllers return new ObjectResult(customer); } + [HttpPatch] + public IActionResult JsonPatchWithoutModelState([FromBody] JsonPatchDocument patchDoc) + { + var customer = CreateCustomer(); + + patchDoc.ApplyTo(customer); + + return new ObjectResult(customer); + } + private Customer CreateCustomer() { return new Customer @@ -52,11 +69,11 @@ namespace JsonPatchWebSite.Controllers { new Order { - OrderName = "Order1" + OrderName = "Order0" }, new Order { - OrderName = "Order2" + OrderName = "Order1" } } };