CommaDelimitedArrayModelBinderTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Specialized;
  4. using System.Globalization;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Jellyfin.Api.ModelBinders;
  8. using MediaBrowser.Controller.Entities;
  9. using Microsoft.AspNetCore.Http;
  10. using Microsoft.AspNetCore.Mvc.ModelBinding;
  11. using Microsoft.Extensions.Primitives;
  12. using Moq;
  13. using Xunit;
  14. using Xunit.Sdk;
  15. namespace Jellyfin.Api.Tests.ModelBinders
  16. {
  17. public sealed class CommaDelimitedArrayModelBinderTests
  18. {
  19. [Fact]
  20. public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedStringArrayQuery()
  21. {
  22. var queryParamName = "test";
  23. var queryParamValues = new string[] { "lol", "xd" };
  24. var queryParamString = "lol,xd";
  25. var queryParamType = typeof(string[]);
  26. var modelBinder = new CommaDelimitedArrayModelBinder();
  27. var valueProvider = new QueryStringValueProvider(
  28. new BindingSource(string.Empty, string.Empty, false, false),
  29. new QueryCollection(new Dictionary<string, StringValues>() { { queryParamName, new StringValues(queryParamString) } }),
  30. CultureInfo.InvariantCulture);
  31. var bindingContextMock = new Mock<ModelBindingContext>();
  32. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  33. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  34. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  35. bindingContextMock.SetupProperty(b => b.Result);
  36. await modelBinder.BindModelAsync(bindingContextMock.Object);
  37. Assert.True(bindingContextMock.Object.Result.IsModelSet);
  38. Assert.Equal((string[])bindingContextMock.Object.Result.Model, queryParamValues);
  39. }
  40. [Fact]
  41. public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedIntArrayQuery()
  42. {
  43. var queryParamName = "test";
  44. var queryParamValues = new int[] { 42, 0 };
  45. var queryParamString = "42,0";
  46. var queryParamType = typeof(int[]);
  47. var modelBinder = new CommaDelimitedArrayModelBinder();
  48. var valueProvider = new QueryStringValueProvider(
  49. new BindingSource(string.Empty, string.Empty, false, false),
  50. new QueryCollection(new Dictionary<string, StringValues>() { { queryParamName, new StringValues(queryParamString) } }),
  51. CultureInfo.InvariantCulture);
  52. var bindingContextMock = new Mock<ModelBindingContext>();
  53. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  54. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  55. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  56. bindingContextMock.SetupProperty(b => b.Result);
  57. await modelBinder.BindModelAsync(bindingContextMock.Object);
  58. Assert.True(bindingContextMock.Object.Result.IsModelSet);
  59. Assert.Equal((int[])bindingContextMock.Object.Result.Model, queryParamValues);
  60. }
  61. [Fact]
  62. public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQuery()
  63. {
  64. var queryParamName = "test";
  65. var queryParamValues = new TestType[] { TestType.How, TestType.Much };
  66. var queryParamString = "How,Much";
  67. var queryParamType = typeof(TestType[]);
  68. var modelBinder = new CommaDelimitedArrayModelBinder();
  69. var valueProvider = new QueryStringValueProvider(
  70. new BindingSource(string.Empty, string.Empty, false, false),
  71. new QueryCollection(new Dictionary<string, StringValues>() { { queryParamName, new StringValues(queryParamString) } }),
  72. CultureInfo.InvariantCulture);
  73. var bindingContextMock = new Mock<ModelBindingContext>();
  74. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  75. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  76. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  77. bindingContextMock.SetupProperty(b => b.Result);
  78. await modelBinder.BindModelAsync(bindingContextMock.Object);
  79. Assert.True(bindingContextMock.Object.Result.IsModelSet);
  80. Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
  81. }
  82. [Fact]
  83. public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQuery2()
  84. {
  85. var queryParamName = "test";
  86. var queryParamValues = new TestType[] { TestType.How, TestType.Much };
  87. var queryParamString = "How,,Much";
  88. var queryParamType = typeof(TestType[]);
  89. var modelBinder = new CommaDelimitedArrayModelBinder();
  90. var valueProvider = new QueryStringValueProvider(
  91. new BindingSource(string.Empty, string.Empty, false, false),
  92. new QueryCollection(new Dictionary<string, StringValues>() { { queryParamName, new StringValues(queryParamString) } }),
  93. CultureInfo.InvariantCulture);
  94. var bindingContextMock = new Mock<ModelBindingContext>();
  95. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  96. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  97. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  98. bindingContextMock.SetupProperty(b => b.Result);
  99. await modelBinder.BindModelAsync(bindingContextMock.Object);
  100. Assert.True(bindingContextMock.Object.Result.IsModelSet);
  101. Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
  102. }
  103. [Fact]
  104. public async Task BindModelAsync_CorrectlyBindsValidEnumArrayQuery()
  105. {
  106. var queryParamName = "test";
  107. var queryParamValues = new TestType[] { TestType.How, TestType.Much };
  108. var queryParamString1 = "How";
  109. var queryParamString2 = "Much";
  110. var queryParamType = typeof(TestType[]);
  111. var modelBinder = new CommaDelimitedArrayModelBinder();
  112. var valueProvider = new QueryStringValueProvider(
  113. new BindingSource(string.Empty, string.Empty, false, false),
  114. new QueryCollection(new Dictionary<string, StringValues>()
  115. {
  116. { queryParamName, new StringValues(new string[] { queryParamString1, queryParamString2 }) },
  117. }),
  118. CultureInfo.InvariantCulture);
  119. var bindingContextMock = new Mock<ModelBindingContext>();
  120. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  121. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  122. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  123. bindingContextMock.SetupProperty(b => b.Result);
  124. await modelBinder.BindModelAsync(bindingContextMock.Object);
  125. Assert.True(bindingContextMock.Object.Result.IsModelSet);
  126. Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
  127. }
  128. [Fact]
  129. public async Task BindModelAsync_CorrectlyBindsValidEnumArrayQuery2()
  130. {
  131. var queryParamName = "test";
  132. var queryParamValues = Array.Empty<TestType>();
  133. var queryParamType = typeof(TestType[]);
  134. var modelBinder = new CommaDelimitedArrayModelBinder();
  135. var valueProvider = new QueryStringValueProvider(
  136. new BindingSource(string.Empty, string.Empty, false, false),
  137. new QueryCollection(new Dictionary<string, StringValues>()
  138. {
  139. { queryParamName, new StringValues(value: null) },
  140. }),
  141. CultureInfo.InvariantCulture);
  142. var bindingContextMock = new Mock<ModelBindingContext>();
  143. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  144. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  145. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  146. bindingContextMock.SetupProperty(b => b.Result);
  147. await modelBinder.BindModelAsync(bindingContextMock.Object);
  148. Assert.False(bindingContextMock.Object.Result.IsModelSet);
  149. }
  150. [Fact]
  151. public async Task BindModelAsync_ThrowsIfCommaDelimitedEnumArrayQueryIsInvalid()
  152. {
  153. var queryParamName = "test";
  154. var queryParamString = "🔥,😢";
  155. var queryParamType = typeof(TestType[]);
  156. var modelBinder = new CommaDelimitedArrayModelBinder();
  157. var valueProvider = new QueryStringValueProvider(
  158. new BindingSource(string.Empty, string.Empty, false, false),
  159. new QueryCollection(new Dictionary<string, StringValues>() { { queryParamName, new StringValues(queryParamString) } }),
  160. CultureInfo.InvariantCulture);
  161. var bindingContextMock = new Mock<ModelBindingContext>();
  162. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  163. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  164. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  165. bindingContextMock.SetupProperty(b => b.Result);
  166. Func<Task> act = async () => await modelBinder.BindModelAsync(bindingContextMock.Object);
  167. await Assert.ThrowsAsync<FormatException>(act);
  168. }
  169. [Fact]
  170. public async Task BindModelAsync_ThrowsIfCommaDelimitedEnumArrayQueryIsInvalid2()
  171. {
  172. var queryParamName = "test";
  173. var queryParamValues = new TestType[] { TestType.How, TestType.Much };
  174. var queryParamString1 = "How";
  175. var queryParamString2 = "😱";
  176. var queryParamType = typeof(TestType[]);
  177. var modelBinder = new CommaDelimitedArrayModelBinder();
  178. var valueProvider = new QueryStringValueProvider(
  179. new BindingSource(string.Empty, string.Empty, false, false),
  180. new QueryCollection(new Dictionary<string, StringValues>()
  181. {
  182. { queryParamName, new StringValues(new string[] { queryParamString1, queryParamString2 }) },
  183. }),
  184. CultureInfo.InvariantCulture);
  185. var bindingContextMock = new Mock<ModelBindingContext>();
  186. bindingContextMock.Setup(b => b.ValueProvider).Returns(valueProvider);
  187. bindingContextMock.Setup(b => b.ModelName).Returns(queryParamName);
  188. bindingContextMock.Setup(b => b.ModelType).Returns(queryParamType);
  189. bindingContextMock.SetupProperty(b => b.Result);
  190. Func<Task> act = async () => await modelBinder.BindModelAsync(bindingContextMock.Object);
  191. await Assert.ThrowsAsync<FormatException>(act);
  192. }
  193. }
  194. }