PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/MongoDB.Driver.Tests/IFindFluentExtensionsTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 403 lines | 314 code | 74 blank | 15 comment | 8 complexity | 06c9d3bf73e21b6a02a0db96f30e694b MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Linq.Expressions;
  17. using System.Threading;
  18. using System.Threading.Tasks;
  19. using MongoDB.Bson;
  20. using MongoDB.Bson.Serialization;
  21. using MongoDB.Bson.Serialization.Serializers;
  22. using MongoDB.Driver.Linq.Translators;
  23. using FluentAssertions;
  24. using Moq;
  25. using Xunit;
  26. using MongoDB.Bson.TestHelpers.XunitExtensions;
  27. namespace MongoDB.Driver.Tests
  28. {
  29. public class IFindFluentExtensionsTests
  30. {
  31. // public methods
  32. [Theory]
  33. [ParameterAttributeData]
  34. public void First_should_add_limit_and_call_ToCursor(
  35. [Values(false, true)] bool async)
  36. {
  37. var mockSubject1 = new Mock<IFindFluent<Person, Person>>();
  38. var mockSubject2 = new Mock<IFindFluent<Person, Person>>();
  39. var mockCursor = new Mock<IAsyncCursor<Person>>();
  40. var firstBatch = new Person[]
  41. {
  42. new Person { FirstName = "John" },
  43. new Person { FirstName = "Jane" }
  44. };
  45. var cancellationToken = new CancellationTokenSource().Token;
  46. mockSubject1.Setup(s => s.Limit(1)).Returns(mockSubject2.Object);
  47. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  48. Person result;
  49. if (async)
  50. {
  51. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  52. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  53. result = mockSubject1.Object.FirstAsync(cancellationToken).GetAwaiter().GetResult();
  54. }
  55. else
  56. {
  57. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  58. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  59. result = mockSubject1.Object.First(cancellationToken);
  60. }
  61. result.FirstName.Should().Be("John");
  62. }
  63. [Theory]
  64. [ParameterAttributeData]
  65. public void First_should_throw_when_find_is_null(
  66. [Values(false, true)] bool async)
  67. {
  68. IFindFluent<Person, Person> subject = null;
  69. Action action;
  70. if (async)
  71. {
  72. action = () => subject.FirstAsync().GetAwaiter().GetResult();
  73. }
  74. else
  75. {
  76. action = () => subject.First();
  77. }
  78. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("find");
  79. }
  80. [Theory]
  81. [ParameterAttributeData]
  82. public void FirstOrDefault_should_add_limit_and_call_ToCursor(
  83. [Values(false, true)] bool async)
  84. {
  85. var mockSubject1 = new Mock<IFindFluent<Person, Person>>();
  86. var mockSubject2 = new Mock<IFindFluent<Person, Person>>();
  87. var mockCursor = new Mock<IAsyncCursor<Person>>();
  88. var firstBatch = new Person[]
  89. {
  90. new Person { FirstName = "John" },
  91. new Person { FirstName = "Jane" }
  92. };
  93. var cancellationToken = new CancellationTokenSource().Token;
  94. mockSubject1.Setup(s => s.Limit(1)).Returns(mockSubject2.Object);
  95. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  96. Person result;
  97. if (async)
  98. {
  99. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  100. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  101. result = mockSubject1.Object.FirstOrDefaultAsync(cancellationToken).GetAwaiter().GetResult();
  102. }
  103. else
  104. {
  105. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  106. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  107. result = mockSubject1.Object.FirstOrDefault(cancellationToken);
  108. }
  109. result.FirstName.Should().Be("John");
  110. }
  111. [Theory]
  112. [ParameterAttributeData]
  113. public void FirstOrDefault_should_throw_when_find_is_null(
  114. [Values(false, true)] bool async)
  115. {
  116. IFindFluent<Person, Person> subject = null;
  117. Action action;
  118. if (async)
  119. {
  120. action = () => subject.FirstOrDefaultAsync().GetAwaiter().GetResult();
  121. }
  122. else
  123. {
  124. action = () => subject.FirstOrDefault();
  125. }
  126. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("find");
  127. }
  128. [Fact]
  129. public void Project_should_generate_the_correct_fields_when_a_BsonDocument_is_used()
  130. {
  131. var subject = CreateSubject()
  132. .Project(BsonDocument.Parse("{_id: 1, Tags: 1}"));
  133. var expectedProjection = BsonDocument.Parse("{_id: 1, Tags: 1}");
  134. AssertProjection(subject, expectedProjection);
  135. }
  136. [Fact]
  137. public void Project_should_generate_the_correct_fields_when_a_string_is_used()
  138. {
  139. var subject = CreateSubject()
  140. .Project("{_id: 1, Tags: 1}");
  141. var expectedProjection = BsonDocument.Parse("{_id: 1, Tags: 1}");
  142. AssertProjection(subject, expectedProjection);
  143. }
  144. [Fact]
  145. public void Project_should_generate_the_correct_fields_and_assign_the_correct_result_serializer()
  146. {
  147. var subject = CreateSubject()
  148. .Project(x => x.FirstName + " " + x.LastName);
  149. var expectedProjection = BsonDocument.Parse("{FirstName: 1, LastName: 1, _id: 0}");
  150. AssertProjection(subject, expectedProjection);
  151. }
  152. [Theory]
  153. [ParameterAttributeData]
  154. public void Single_should_add_limit_and_call_ToCursor(
  155. [Values(false, true)] bool async)
  156. {
  157. var mockSubject1 = new Mock<IFindFluent<Person, Person>>();
  158. var mockSubject2 = new Mock<IFindFluent<Person, Person>>();
  159. var findOptions = new FindOptions<Person, Person>();
  160. var mockCursor = new Mock<IAsyncCursor<Person>>();
  161. var firstBatch = new Person[]
  162. {
  163. new Person { FirstName = "John" }
  164. };
  165. var cancellationToken = new CancellationTokenSource().Token;
  166. mockSubject1.SetupGet(s => s.Options).Returns(findOptions);
  167. mockSubject1.Setup(s => s.Limit(2)).Returns(mockSubject2.Object);
  168. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  169. Person result;
  170. if (async)
  171. {
  172. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  173. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  174. result = mockSubject1.Object.SingleAsync(cancellationToken).GetAwaiter().GetResult();
  175. }
  176. else
  177. {
  178. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  179. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  180. result = mockSubject1.Object.Single(cancellationToken);
  181. }
  182. result.FirstName.Should().Be("John");
  183. }
  184. [Theory]
  185. [ParameterAttributeData]
  186. public void Single_should_throw_when_find_is_null(
  187. [Values(false, true)] bool async)
  188. {
  189. IFindFluent<Person, Person> subject = null;
  190. Action action;
  191. if (async)
  192. {
  193. action = () => subject.SingleAsync().GetAwaiter().GetResult();
  194. }
  195. else
  196. {
  197. action = () => subject.Single();
  198. }
  199. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("find");
  200. }
  201. [Theory]
  202. [ParameterAttributeData]
  203. public void SingleOrDefault_should_add_limit_and_call_ToCursor(
  204. [Values(false, true)] bool async)
  205. {
  206. var mockSubject1 = new Mock<IFindFluent<Person, Person>>();
  207. var mockSubject2 = new Mock<IFindFluent<Person, Person>>();
  208. var findOptions = new FindOptions<Person, Person>();
  209. var mockCursor = new Mock<IAsyncCursor<Person>>();
  210. var firstBatch = new Person[]
  211. {
  212. new Person { FirstName = "John" }
  213. };
  214. var cancellationToken = new CancellationTokenSource().Token;
  215. mockSubject1.SetupGet(s => s.Options).Returns(findOptions);
  216. mockSubject1.Setup(s => s.Limit(2)).Returns(mockSubject2.Object);
  217. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  218. Person result;
  219. if (async)
  220. {
  221. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  222. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  223. result = mockSubject1.Object.SingleOrDefaultAsync(cancellationToken).GetAwaiter().GetResult();
  224. }
  225. else
  226. {
  227. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  228. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  229. result = mockSubject1.Object.SingleOrDefault(cancellationToken);
  230. }
  231. result.FirstName.Should().Be("John");
  232. }
  233. [Theory]
  234. [ParameterAttributeData]
  235. public void SingleOrDefault_should_throw_when_find_is_null(
  236. [Values(false, true)] bool async)
  237. {
  238. IFindFluent<Person, Person> subject = null;
  239. Action action;
  240. if (async)
  241. {
  242. action = () => subject.SingleOrDefaultAsync().GetAwaiter().GetResult();
  243. }
  244. else
  245. {
  246. action = () => subject.SingleOrDefault();
  247. }
  248. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("find");
  249. }
  250. [Fact]
  251. public void SortBy_should_generate_the_correct_sort()
  252. {
  253. var subject = CreateSubject();
  254. subject.SortBy(x => x.FirstName);
  255. var expectedSort = BsonDocument.Parse("{FirstName: 1}");
  256. AssertSort(subject, expectedSort);
  257. }
  258. [Fact]
  259. public void SortBy_ThenBy_should_generate_the_correct_sort()
  260. {
  261. var subject = CreateSubject();
  262. subject.SortBy(x => x.FirstName).ThenBy(x => x.LastName);
  263. var expectedSort = BsonDocument.Parse("{FirstName: 1, LastName: 1}");
  264. AssertSort(subject, expectedSort);
  265. }
  266. [Fact]
  267. public void SortBy_ThenByDescending_should_generate_the_correct_sort()
  268. {
  269. var subject = CreateSubject();
  270. subject.SortBy(x => x.FirstName).ThenByDescending(x => x.LastName);
  271. var expectedSort = BsonDocument.Parse("{FirstName: 1, LastName: -1}");
  272. AssertSort(subject, expectedSort);
  273. }
  274. [Fact]
  275. public void SortBy_ThenBy_ThenBy_should_generate_the_correct_sort()
  276. {
  277. var subject = CreateSubject();
  278. subject.SortBy(x => x.FirstName).ThenBy(x => x.LastName).ThenBy(x => x.Age);
  279. var expectedSort = BsonDocument.Parse("{FirstName: 1, LastName: 1, Age: 1}");
  280. AssertSort(subject, expectedSort);
  281. }
  282. [Fact]
  283. public void SortByDescending_should_generate_the_correct_sort()
  284. {
  285. var subject = CreateSubject();
  286. subject.SortByDescending(x => x.FirstName);
  287. var expectedSort = BsonDocument.Parse("{FirstName: -1}");
  288. AssertSort(subject, expectedSort);
  289. }
  290. [Fact]
  291. public void SortByDescending_ThenBy_should_generate_the_correct_sort()
  292. {
  293. var subject = CreateSubject();
  294. subject.SortByDescending(x => x.FirstName).ThenBy(x => x.LastName);
  295. var expectedSort = BsonDocument.Parse("{FirstName: -1, LastName: 1}");
  296. AssertSort(subject, expectedSort);
  297. }
  298. [Fact]
  299. public void SortByDescending_ThenByDescending_should_generate_the_correct_sort()
  300. {
  301. var subject = CreateSubject();
  302. subject.SortByDescending(x => x.FirstName).ThenByDescending(x => x.LastName);
  303. var expectedSort = BsonDocument.Parse("{FirstName: -1, LastName: -1}");
  304. AssertSort(subject, expectedSort);
  305. }
  306. private static void AssertProjection<TResult>(IFindFluent<Person, TResult> subject, BsonDocument expectedProjection)
  307. {
  308. Assert.Equal(expectedProjection, subject.Options.Projection.Render(BsonSerializer.SerializerRegistry.GetSerializer<Person>(), BsonSerializer.SerializerRegistry).Document);
  309. }
  310. private static void AssertSort(IFindFluent<Person, Person> subject, BsonDocument expectedSort)
  311. {
  312. Assert.Equal(expectedSort, subject.Options.Sort.Render(BsonSerializer.SerializerRegistry.GetSerializer<Person>(), BsonSerializer.SerializerRegistry));
  313. }
  314. private IFindFluent<Person, Person> CreateSubject()
  315. {
  316. var settings = new MongoCollectionSettings();
  317. var mockCollection = new Mock<IMongoCollection<Person>>();
  318. mockCollection.SetupGet(c => c.Settings).Returns(settings);
  319. var options = new FindOptions<Person, Person>();
  320. return new FindFluent<Person, Person>(session: null, collection: mockCollection.Object, filter: new BsonDocument(), options: options);
  321. }
  322. public class Person
  323. {
  324. public string FirstName;
  325. public string LastName;
  326. public int Age;
  327. }
  328. }
  329. }