PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/MongoDB.Driver.Tests/FindFluentTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 402 lines | 357 code | 30 blank | 15 comment | 12 complexity | 2b07bb9e5615e09dac09061908cd1131 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.Reflection;
  17. using System.Threading;
  18. using FluentAssertions;
  19. using MongoDB.Bson;
  20. using MongoDB.Bson.Serialization;
  21. using MongoDB.Bson.Serialization.Serializers;
  22. using MongoDB.Bson.TestHelpers.XunitExtensions;
  23. using Moq;
  24. using Xunit;
  25. namespace MongoDB.Driver.Tests
  26. {
  27. public class FindFluentTests
  28. {
  29. private Mock<IMongoCollection<Person>> _mockCollection;
  30. [Theory]
  31. [ParameterAttributeData]
  32. public void As_should_change_the_result_type(
  33. [Values(false, true)] bool async)
  34. {
  35. var subject = CreateSubject();
  36. var result = subject.As<BsonDocument>();
  37. Predicate<FindOptions<Person, BsonDocument>> hasExpectedProjection = options =>
  38. {
  39. var serializerRegistry = BsonSerializer.SerializerRegistry;
  40. var sourceSerializer = serializerRegistry.GetSerializer<Person>();
  41. var renderedProjection = options.Projection.Render(sourceSerializer, serializerRegistry);
  42. return renderedProjection.Document == null && renderedProjection.ProjectionSerializer is BsonDocumentSerializer;
  43. };
  44. if (async)
  45. {
  46. result.ToCursorAsync().GetAwaiter().GetResult();
  47. _mockCollection.Verify(
  48. c => c.FindAsync<BsonDocument>(
  49. subject.Filter,
  50. It.Is<FindOptions<Person, BsonDocument>>(options => hasExpectedProjection(options)),
  51. CancellationToken.None),
  52. Times.Once);
  53. }
  54. else
  55. {
  56. result.ToCursor();
  57. _mockCollection.Verify(
  58. c => c.FindSync<BsonDocument>(
  59. subject.Filter,
  60. It.Is<FindOptions<Person, BsonDocument>>(options => hasExpectedProjection(options)),
  61. CancellationToken.None),
  62. Times.Once);
  63. }
  64. }
  65. [Theory]
  66. [ParameterAttributeData]
  67. public void Count_should_call_collection_Count(
  68. [Values(false, true)] bool usingSession,
  69. [Values(false, true)] bool async)
  70. {
  71. var session = CreateSession(usingSession);
  72. var filter = new BsonDocumentFilterDefinition<Person>(new BsonDocument("filter", 1));
  73. var hint = new BsonDocument("hint", 1);
  74. var findOptions = new FindOptions<Person>
  75. {
  76. Collation = new Collation("en-us"),
  77. Limit = 1,
  78. MaxTime = TimeSpan.FromSeconds(2),
  79. #pragma warning disable 618
  80. Modifiers = new BsonDocument("$hint", hint),
  81. #pragma warning restore 618
  82. Skip = 3
  83. };
  84. var subject = CreateSubject(session: session, filter: filter, options: findOptions);
  85. var cancellationToken = new CancellationTokenSource().Token;
  86. Predicate<CountOptions> matchesExpectedOptions = countOptions =>
  87. countOptions.Collation.Equals(findOptions.Collation) &&
  88. countOptions.Hint.Equals(hint) &&
  89. countOptions.Limit.Equals((long?)findOptions.Limit) &&
  90. countOptions.MaxTime.Equals(findOptions.MaxTime) &&
  91. countOptions.Skip.Equals((long?)findOptions.Skip);
  92. if (async)
  93. {
  94. if (usingSession)
  95. {
  96. #pragma warning disable 618
  97. subject.CountAsync(cancellationToken).GetAwaiter().GetResult();
  98. _mockCollection.Verify(
  99. m => m.CountAsync(
  100. session,
  101. filter,
  102. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  103. cancellationToken),
  104. Times.Once);
  105. #pragma warning restore
  106. }
  107. else
  108. {
  109. #pragma warning disable 618
  110. subject.CountAsync(cancellationToken).GetAwaiter().GetResult();
  111. _mockCollection.Verify(
  112. m => m.CountAsync(
  113. filter,
  114. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  115. cancellationToken),
  116. Times.Once);
  117. }
  118. #pragma warning restore
  119. }
  120. else
  121. {
  122. if (usingSession)
  123. {
  124. #pragma warning disable 618
  125. subject.Count(cancellationToken);
  126. _mockCollection.Verify(
  127. m => m.Count(
  128. session,
  129. filter,
  130. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  131. cancellationToken),
  132. Times.Once);
  133. #pragma warning restore
  134. }
  135. else
  136. {
  137. #pragma warning disable 618
  138. subject.Count(cancellationToken);
  139. _mockCollection.Verify(
  140. m => m.Count(
  141. filter,
  142. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  143. cancellationToken),
  144. Times.Once);
  145. #pragma warning restore
  146. }
  147. }
  148. }
  149. [Theory]
  150. [ParameterAttributeData]
  151. public void CountDocuments_should_call_collection_CountDocuments(
  152. [Values(false, true)] bool usingSession,
  153. [Values(false, true)] bool async)
  154. {
  155. var session = CreateSession(usingSession);
  156. var filter = new BsonDocumentFilterDefinition<Person>(new BsonDocument("filter", 1));
  157. var hint = new BsonDocument("hint", 1);
  158. var findOptions = new FindOptions<Person>
  159. {
  160. Collation = new Collation("en-us"),
  161. Limit = 1,
  162. MaxTime = TimeSpan.FromSeconds(2),
  163. #pragma warning disable 618
  164. Modifiers = new BsonDocument("$hint", hint),
  165. #pragma warning restore 618
  166. Skip = 3
  167. };
  168. var subject = CreateSubject(session: session, filter: filter, options: findOptions);
  169. var cancellationToken = new CancellationTokenSource().Token;
  170. Predicate<CountOptions> matchesExpectedOptions = countOptions =>
  171. countOptions.Collation.Equals(findOptions.Collation) &&
  172. countOptions.Hint.Equals(hint) &&
  173. countOptions.Limit.Equals((long?)findOptions.Limit) &&
  174. countOptions.MaxTime.Equals(findOptions.MaxTime) &&
  175. countOptions.Skip.Equals((long?)findOptions.Skip);
  176. if (async)
  177. {
  178. if (usingSession)
  179. {
  180. subject.CountDocumentsAsync(cancellationToken).GetAwaiter().GetResult();
  181. _mockCollection.Verify(
  182. m => m.CountDocumentsAsync(
  183. session,
  184. filter,
  185. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  186. cancellationToken),
  187. Times.Once);
  188. }
  189. else
  190. {
  191. subject.CountDocumentsAsync(cancellationToken).GetAwaiter().GetResult();
  192. _mockCollection.Verify(
  193. m => m.CountDocumentsAsync(
  194. filter,
  195. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  196. cancellationToken),
  197. Times.Once);
  198. }
  199. }
  200. else
  201. {
  202. if (usingSession)
  203. {
  204. subject.CountDocuments(cancellationToken);
  205. _mockCollection.Verify(
  206. m => m.CountDocuments(
  207. session,
  208. filter,
  209. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  210. cancellationToken),
  211. Times.Once);
  212. }
  213. else
  214. {
  215. subject.CountDocuments(cancellationToken);
  216. _mockCollection.Verify(
  217. m => m.CountDocuments(
  218. filter,
  219. It.Is<CountOptions>(o => matchesExpectedOptions(o)),
  220. cancellationToken),
  221. Times.Once);
  222. }
  223. }
  224. }
  225. [Theory]
  226. [ParameterAttributeData]
  227. public void ToCursor_should_call_collection_Find_with_expected_arguments(
  228. [Values(false, true)] bool usingSession,
  229. [Values(false, true)] bool async)
  230. {
  231. var session = usingSession ? new Mock<IClientSessionHandle>().Object : null;
  232. var filter = Builders<Person>.Filter.Eq("_id", 1);
  233. var options = new FindOptions<Person, Person>();
  234. var subject = CreateSubject(session, filter, options);
  235. var cancellationToken = new CancellationTokenSource().Token;
  236. if (async)
  237. {
  238. var _ = subject.ToCursorAsync(cancellationToken).GetAwaiter().GetResult();
  239. if (usingSession)
  240. {
  241. _mockCollection.Verify(
  242. collection => collection.FindAsync(
  243. session,
  244. filter,
  245. options,
  246. cancellationToken),
  247. Times.Once);
  248. }
  249. else
  250. {
  251. _mockCollection.Verify(
  252. collection => collection.FindAsync(
  253. filter,
  254. options,
  255. cancellationToken),
  256. Times.Once);
  257. }
  258. }
  259. else
  260. {
  261. var _ = subject.ToCursor(cancellationToken);
  262. if (usingSession)
  263. {
  264. _mockCollection.Verify(
  265. collection => collection.FindSync(
  266. session,
  267. filter,
  268. options,
  269. cancellationToken),
  270. Times.Once);
  271. }
  272. else
  273. {
  274. _mockCollection.Verify(
  275. collection => collection.FindSync(
  276. filter,
  277. options,
  278. cancellationToken),
  279. Times.Once);
  280. }
  281. }
  282. }
  283. [Fact]
  284. public void ToString_should_return_the_correct_string()
  285. {
  286. var subject = CreateSubject();
  287. subject.Filter = new BsonDocument("Age", 20);
  288. subject.Options.Collation = new Collation("en_US");
  289. subject.Options.Comment = "awesome";
  290. subject.Options.Hint = "x_3";
  291. subject.Options.Max = new BsonDocument("max", 5);
  292. subject.Options.MaxTime = TimeSpan.FromSeconds(2);
  293. #pragma warning disable 618
  294. subject.Options.Modifiers = new BsonDocument
  295. {
  296. { "$explain", true },
  297. { "$hint", "ix_1" }
  298. };
  299. #pragma warning restore 618
  300. subject.Options.Min = new BsonDocument("min", 2);
  301. subject.Options.ReturnKey = true;
  302. subject.Options.ShowRecordId = true;
  303. var find = subject
  304. .SortBy(x => x.LastName)
  305. .ThenByDescending(x => x.FirstName)
  306. .Skip(2)
  307. .Limit(10)
  308. .Project(x => x.FirstName + " " + x.LastName);
  309. var str = find.ToString();
  310. str.Should().Be(
  311. "find({ \"Age\" : 20 }, { \"FirstName\" : 1, \"LastName\" : 1, \"_id\" : 0 })" +
  312. ".collation({ \"locale\" : \"en_US\" })" +
  313. ".sort({ \"LastName\" : 1, \"FirstName\" : -1 })" +
  314. ".skip(2)" +
  315. ".limit(10)" +
  316. ".maxTime(2000)" +
  317. ".hint(x_3)" +
  318. ".max({ \"max\" : 5 })" +
  319. ".min({ \"min\" : 2 })" +
  320. ".returnKey(true)" +
  321. ".showRecordId(true)" +
  322. "._addSpecial(\"$comment\", \"awesome\")" +
  323. "._addSpecial(\"$explain\", true)" +
  324. "._addSpecial(\"$hint\", \"ix_1\")");
  325. }
  326. // private methods
  327. private IClientSessionHandle CreateSession(bool usingSession)
  328. {
  329. return usingSession ? Mock.Of<IClientSessionHandle>() : null;
  330. }
  331. private IFindFluent<Person, Person> CreateSubject(IClientSessionHandle session = null, FilterDefinition<Person> filter = null, FindOptions<Person, Person> options = null)
  332. {
  333. var settings = new MongoCollectionSettings();
  334. _mockCollection = new Mock<IMongoCollection<Person>>();
  335. _mockCollection.SetupGet(c => c.DocumentSerializer).Returns(BsonSerializer.SerializerRegistry.GetSerializer<Person>());
  336. _mockCollection.SetupGet(c => c.Settings).Returns(settings);
  337. filter = filter ?? new BsonDocument();
  338. options = options ?? new FindOptions<Person, Person>();
  339. var subject = new FindFluent<Person, Person>(session: session, collection: _mockCollection.Object, filter: filter, options: options);
  340. return subject;
  341. }
  342. public class Person
  343. {
  344. public string FirstName;
  345. public string LastName;
  346. public int Age;
  347. }
  348. }
  349. internal static class FindFluentReflector
  350. {
  351. public static IMongoCollection<TDocument> _collection<TDocument, TProjection>(this FindFluent<TDocument, TProjection> obj)
  352. {
  353. var fieldInfo = typeof(FindFluent<TDocument, TProjection>).GetField("_collection", BindingFlags.NonPublic | BindingFlags.Instance);
  354. return (IMongoCollection<TDocument>)fieldInfo.GetValue(obj);
  355. }
  356. public static FilterDefinition<TDocument> _filter<TDocument, TProjection>(this FindFluent<TDocument, TProjection> obj)
  357. {
  358. var fieldInfo = typeof(FindFluent<TDocument, TProjection>).GetField("_filter", BindingFlags.NonPublic | BindingFlags.Instance);
  359. return (FilterDefinition<TDocument>)fieldInfo.GetValue(obj);
  360. }
  361. public static FindOptions<TDocument, TProjection> _options<TDocument, TProjection>(this FindFluent<TDocument, TProjection> obj)
  362. {
  363. var fieldInfo = typeof(FindFluent<TDocument, TProjection>).GetField("_options", BindingFlags.NonPublic | BindingFlags.Instance);
  364. return (FindOptions<TDocument, TProjection>)fieldInfo.GetValue(obj);
  365. }
  366. public static IClientSessionHandle _session<TDocument, TProjection>(this FindFluent<TDocument, TProjection> obj)
  367. {
  368. var fieldInfo = typeof(FindFluent<TDocument, TProjection>).GetField("_session", BindingFlags.NonPublic | BindingFlags.Instance);
  369. return (IClientSessionHandle)fieldInfo.GetValue(obj);
  370. }
  371. }
  372. }