PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/MongoDB.Driver.Tests/IAggregateFluentExtensionsTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 700 lines | 542 code | 141 blank | 17 comment | 8 complexity | 8535ed52ec756cf6b9fbdac8518e376e 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 FluentAssertions;
  16. using MongoDB.Bson;
  17. using MongoDB.Bson.Serialization;
  18. using MongoDB.Bson.Serialization.Serializers;
  19. using MongoDB.Bson.TestHelpers.XunitExtensions;
  20. using MongoDB.Driver.Core.Bindings;
  21. using MongoDB.Driver.Core.Misc;
  22. using MongoDB.Driver.Core.Operations;
  23. using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
  24. using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
  25. using Moq;
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Linq;
  29. using System.Threading;
  30. using System.Threading.Tasks;
  31. using Xunit;
  32. namespace MongoDB.Driver.Tests
  33. {
  34. public class IAggregateFluentExtensionsTests
  35. {
  36. // public methods
  37. [Theory]
  38. [ParameterAttributeData]
  39. public void First_should_add_limit_and_call_ToCursor(
  40. [Values(false, true)] bool async)
  41. {
  42. var mockSubject1 = new Mock<IAggregateFluent<Person>>();
  43. var mockSubject2 = new Mock<IAggregateFluent<Person>>();
  44. var mockCursor = new Mock<IAsyncCursor<Person>>();
  45. var firstBatch = new Person[]
  46. {
  47. new Person { FirstName = "John" },
  48. new Person { FirstName = "Jane" }
  49. };
  50. var cancellationToken = new CancellationTokenSource().Token;
  51. mockSubject1.Setup(s => s.Limit(1)).Returns(mockSubject2.Object);
  52. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  53. Person result;
  54. if (async)
  55. {
  56. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  57. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  58. result = mockSubject1.Object.FirstAsync(cancellationToken).GetAwaiter().GetResult();
  59. }
  60. else
  61. {
  62. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  63. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  64. result = mockSubject1.Object.First(cancellationToken);
  65. }
  66. result.FirstName.Should().Be("John");
  67. }
  68. [Theory]
  69. [ParameterAttributeData]
  70. public void First_should_throw_when_aggregate_is_null(
  71. [Values(false, true)] bool async)
  72. {
  73. IAggregateFluent<Person> subject = null;
  74. Action action;
  75. if (async)
  76. {
  77. action = () => subject.FirstAsync().GetAwaiter().GetResult();
  78. }
  79. else
  80. {
  81. action = () => subject.First();
  82. }
  83. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("aggregate");
  84. }
  85. [Theory]
  86. [ParameterAttributeData]
  87. public void FirstOrDefault_should_add_limit_and_call_ToCursor(
  88. [Values(false, true)] bool async)
  89. {
  90. var mockSubject1 = new Mock<IAggregateFluent<Person>>();
  91. var mockSubject2 = new Mock<IAggregateFluent<Person>>();
  92. var mockCursor = new Mock<IAsyncCursor<Person>>();
  93. var firstBatch = new Person[]
  94. {
  95. new Person { FirstName = "John" },
  96. new Person { FirstName = "Jane" }
  97. };
  98. var cancellationToken = new CancellationTokenSource().Token;
  99. mockSubject1.Setup(s => s.Limit(1)).Returns(mockSubject2.Object);
  100. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  101. Person result;
  102. if (async)
  103. {
  104. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  105. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  106. result = mockSubject1.Object.FirstOrDefaultAsync(cancellationToken).GetAwaiter().GetResult();
  107. }
  108. else
  109. {
  110. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  111. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  112. result = mockSubject1.Object.FirstOrDefault(cancellationToken);
  113. }
  114. result.FirstName.Should().Be("John");
  115. }
  116. [Theory]
  117. [ParameterAttributeData]
  118. public void FirstOrDefault_should_throw_when_aggregate_is_null(
  119. [Values(false, true)] bool async)
  120. {
  121. IAggregateFluent<Person> subject = null;
  122. Action action;
  123. if (async)
  124. {
  125. action = () => subject.FirstOrDefaultAsync().GetAwaiter().GetResult();
  126. }
  127. else
  128. {
  129. action = () => subject.FirstOrDefault();
  130. }
  131. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("aggregate");
  132. }
  133. [Fact]
  134. public void Group_should_generate_the_correct_group_when_a_result_type_is_not_specified()
  135. {
  136. var subject = CreateSubject()
  137. .Group("{_id: \"$Tags\" }");
  138. var expectedGroup = BsonDocument.Parse("{$group: {_id: '$Tags'}}");
  139. AssertLast(subject, expectedGroup);
  140. }
  141. [Fact]
  142. public void Group_should_generate_the_correct_document_using_expressions()
  143. {
  144. var subject = CreateSubject()
  145. .Group(x => x.Age, g => new { Name = g.Select(x => x.FirstName + " " + x.LastName).First() });
  146. var expectedGroup = BsonDocument.Parse("{$group: {_id: '$Age', Name: {'$first': { '$concat': ['$FirstName', ' ', '$LastName']}}}}");
  147. AssertLast(subject, expectedGroup);
  148. }
  149. [Fact]
  150. public void Lookup_should_generate_the_correct_group_when_using_BsonDocument()
  151. {
  152. var subject = CreateSubject()
  153. .Lookup("from", "local", "foreign", "as");
  154. var expectedLookup = BsonDocument.Parse("{$lookup: { from: 'from', localField: 'local', foreignField: 'foreign', as: 'as' } }");
  155. AssertLast(subject, expectedLookup);
  156. }
  157. [Fact]
  158. public void Lookup_should_generate_the_correct_group_when_using_lambdas()
  159. {
  160. var subject = CreateSubject()
  161. .Lookup<Person, NameMeaning, LookedUpPerson>(
  162. CreateCollection<NameMeaning>(),
  163. x => x.FirstName,
  164. x => x.Name,
  165. x => x.Meanings);
  166. var expectedLookup = BsonDocument.Parse("{$lookup: { from: 'NameMeaning', localField: 'FirstName', foreignField: 'Name', as: 'Meanings' } }");
  167. AssertLast(subject, expectedLookup);
  168. }
  169. [SkippableFact]
  170. public void Lookup_expressive_should_generate_the_correct_lookup_when_using_BsonDocument()
  171. {
  172. RequireServer.Check().Supports(Feature.AggregateLet);
  173. var subject = CreateSubject().Lookup(
  174. CreateCollection<BsonDocument>("foreign"),
  175. new BsonDocument("name", "value"),
  176. new EmptyPipelineDefinition<BsonDocument>(),
  177. "as");
  178. var expectedLookup = BsonDocument.Parse("{ $lookup : { from : 'foreign', let : { 'name' : 'value' }, pipeline : [ ], as : 'as' } }");
  179. AssertLast(subject, expectedLookup);
  180. }
  181. [SkippableFact]
  182. public void Lookup_expressive_should_generate_the_correct_lookup_when_using_lambdas()
  183. {
  184. RequireServer.Check().Supports(Feature.AggregateLet);
  185. var subject = CreateSubject()
  186. .Lookup<Person, NameMeaning, NameMeaning, IEnumerable<NameMeaning>, LookedUpPerson>(
  187. CreateCollection<NameMeaning>(),
  188. new BsonDocument("name", "value"),
  189. PipelineDefinition<NameMeaning, NameMeaning>.Create("{}"),
  190. person => person.Meanings);
  191. var expectedLookup = BsonDocument.Parse("{ $lookup : { from : 'NameMeaning', let : { 'name' : 'value' }, pipeline : [ { } ], as : 'Meanings' } }");
  192. AssertLast(subject, expectedLookup);
  193. }
  194. [Fact]
  195. public void Match_should_generate_the_correct_match()
  196. {
  197. var subject = CreateSubject()
  198. .Match(x => x.Age > 20);
  199. var expectedMatch = BsonDocument.Parse("{$match: {Age: {$gt: 20}}}");
  200. AssertLast(subject, expectedMatch);
  201. }
  202. [Fact]
  203. public void Project_should_generate_the_correct_document_when_a_result_type_is_not_specified()
  204. {
  205. var subject = CreateSubject()
  206. .Project(BsonDocument.Parse("{ Awesome: \"$Tags\" }"));
  207. var expectedProject = BsonDocument.Parse("{$project: {Awesome: '$Tags'}}");
  208. AssertLast(subject, expectedProject);
  209. }
  210. [Fact]
  211. public void Project_should_generate_the_correct_document_using_expressions()
  212. {
  213. var subject = CreateSubject()
  214. .Project(x => new { Name = x.FirstName + " " + x.LastName });
  215. var expectedProject = BsonDocument.Parse("{$project: {Name: {'$concat': ['$FirstName', ' ', '$LastName']}, _id: 0}}");
  216. AssertLast(subject, expectedProject);
  217. }
  218. [Fact]
  219. public void ReplaceRoot_should_generate_the_correct_stage()
  220. {
  221. var subject = CreateSubject()
  222. .ReplaceRoot(x => x.PhoneNumber);
  223. var expectedStage = BsonDocument.Parse("{ $replaceRoot : { newRoot: '$PhoneNumber' } }");
  224. AssertLast(subject, expectedStage);
  225. }
  226. [Fact]
  227. public void ReplaceRoot_should_generate_the_correct_stage_with_anonymous_class()
  228. {
  229. var subject = CreateSubject()
  230. .ReplaceRoot(x => new { Name = x.FirstName + " " + x.LastName });
  231. var expectedStage = BsonDocument.Parse("{ $replaceRoot : { newRoot: { Name : { $concat : [ '$FirstName', ' ', '$LastName' ] } } } }");
  232. AssertLast(subject, expectedStage);
  233. }
  234. [Fact]
  235. public void ReplaceWith_should_generate_the_correct_stage()
  236. {
  237. var subject = CreateSubject()
  238. .ReplaceWith(x => x.PhoneNumber);
  239. var expectedStage = BsonDocument.Parse("{ $replaceWith : '$PhoneNumber' }");
  240. AssertLast(subject, expectedStage);
  241. }
  242. [Fact]
  243. public void ReplaceWith_should_generate_the_correct_stage_with_anonymous_class()
  244. {
  245. var subject = CreateSubject()
  246. .ReplaceWith(x => new { Name = x.FirstName + " " + x.LastName });
  247. var expectedStage = BsonDocument.Parse("{ $replaceWith : { Name : { $concat : [ '$FirstName', ' ', '$LastName' ] } } }");
  248. AssertLast(subject, expectedStage);
  249. }
  250. [Theory]
  251. [ParameterAttributeData]
  252. public void Single_should_add_limit_and_call_ToCursor(
  253. [Values(false, true)] bool async)
  254. {
  255. var mockSubject1 = new Mock<IAggregateFluent<Person>>();
  256. var mockSubject2 = new Mock<IAggregateFluent<Person>>();
  257. var mockCursor = new Mock<IAsyncCursor<Person>>();
  258. var firstBatch = new Person[]
  259. {
  260. new Person { FirstName = "John" }
  261. };
  262. var cancellationToken = new CancellationTokenSource().Token;
  263. mockSubject1.Setup(s => s.Limit(2)).Returns(mockSubject2.Object);
  264. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  265. Person result;
  266. if (async)
  267. {
  268. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  269. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  270. result = mockSubject1.Object.SingleAsync(cancellationToken).GetAwaiter().GetResult();
  271. }
  272. else
  273. {
  274. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  275. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  276. result = mockSubject1.Object.Single(cancellationToken);
  277. }
  278. result.FirstName.Should().Be("John");
  279. }
  280. [Theory]
  281. [ParameterAttributeData]
  282. public void Single_should_throw_when_aggregate_is_null(
  283. [Values(false, true)] bool async)
  284. {
  285. IAggregateFluent<Person> subject = null;
  286. Action action;
  287. if (async)
  288. {
  289. action = () => subject.SingleAsync().GetAwaiter().GetResult();
  290. }
  291. else
  292. {
  293. action = () => subject.Single();
  294. }
  295. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("aggregate");
  296. }
  297. [Theory]
  298. [ParameterAttributeData]
  299. public void SingleOrDefault_should_add_limit_and_call_ToCursor(
  300. [Values(false, true)] bool async)
  301. {
  302. var mockSubject1 = new Mock<IAggregateFluent<Person>>();
  303. var mockSubject2 = new Mock<IAggregateFluent<Person>>();
  304. var mockCursor = new Mock<IAsyncCursor<Person>>();
  305. var firstBatch = new Person[]
  306. {
  307. new Person { FirstName = "John" }
  308. };
  309. var cancellationToken = new CancellationTokenSource().Token;
  310. mockSubject1.Setup(s => s.Limit(2)).Returns(mockSubject2.Object);
  311. mockCursor.SetupGet(c => c.Current).Returns(firstBatch);
  312. Person result;
  313. if (async)
  314. {
  315. mockSubject2.Setup(s => s.ToCursorAsync(cancellationToken)).Returns(Task.FromResult(mockCursor.Object));
  316. mockCursor.Setup(c => c.MoveNextAsync(cancellationToken)).Returns(Task.FromResult(true));
  317. result = mockSubject1.Object.SingleOrDefaultAsync(cancellationToken).GetAwaiter().GetResult();
  318. }
  319. else
  320. {
  321. mockSubject2.Setup(s => s.ToCursor(cancellationToken)).Returns(mockCursor.Object);
  322. mockCursor.Setup(c => c.MoveNext(cancellationToken)).Returns(true);
  323. result = mockSubject1.Object.SingleOrDefault(cancellationToken);
  324. }
  325. result.FirstName.Should().Be("John");
  326. }
  327. [Theory]
  328. [ParameterAttributeData]
  329. public void SingleOrDefault_should_throw_when_aggregate_is_null(
  330. [Values(false, true)] bool async)
  331. {
  332. IAggregateFluent<Person> subject = null;
  333. Action action;
  334. if (async)
  335. {
  336. action = () => subject.SingleOrDefaultAsync().GetAwaiter().GetResult();
  337. }
  338. else
  339. {
  340. action = () => subject.SingleOrDefault();
  341. }
  342. action.ShouldThrow<ArgumentNullException>().And.ParamName.Should().Be("aggregate");
  343. }
  344. [Fact]
  345. public void SortBy_should_generate_the_correct_sort()
  346. {
  347. var subject = CreateSubject()
  348. .SortBy(x => x.FirstName);
  349. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: 1}}");
  350. AssertLast(subject, expectedSort);
  351. }
  352. [Fact]
  353. public void SortBy_ThenBy_should_generate_the_correct_sort()
  354. {
  355. var subject = CreateSubject()
  356. .SortBy(x => x.FirstName)
  357. .ThenBy(x => x.LastName);
  358. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: 1, LastName: 1}}");
  359. AssertLast(subject, expectedSort);
  360. }
  361. [Fact]
  362. public void SortBy_ThenByDescending_should_generate_the_correct_sort()
  363. {
  364. var subject = CreateSubject()
  365. .SortBy(x => x.FirstName)
  366. .ThenByDescending(x => x.LastName);
  367. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: 1, LastName: -1}}");
  368. AssertLast(subject, expectedSort);
  369. }
  370. [Fact]
  371. public void SortBy_ThenBy_ThenBy_should_generate_the_correct_sort()
  372. {
  373. var subject = CreateSubject()
  374. .SortBy(x => x.FirstName)
  375. .ThenBy(x => x.LastName)
  376. .ThenBy(x => x.Age);
  377. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: 1, LastName: 1, Age: 1}}");
  378. AssertLast(subject, expectedSort);
  379. }
  380. [Fact]
  381. public void SortByCount_should_generate_the_correct_stage()
  382. {
  383. var subject = CreateSubject()
  384. .SortByCount(x => x.Age);
  385. var expectedStage = BsonDocument.Parse("{ $sortByCount : '$Age' }");
  386. AssertLast(subject, expectedStage);
  387. }
  388. [Fact]
  389. public void SortByDescending_should_generate_the_correct_sort()
  390. {
  391. var subject = CreateSubject()
  392. .SortByDescending(x => x.FirstName);
  393. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: -1}}");
  394. AssertLast(subject, expectedSort);
  395. }
  396. [Fact]
  397. public void SortByDescending_ThenBy_should_generate_the_correct_sort()
  398. {
  399. var subject = CreateSubject()
  400. .SortByDescending(x => x.FirstName)
  401. .ThenBy(x => x.LastName);
  402. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: -1, LastName: 1}}");
  403. AssertLast(subject, expectedSort);
  404. }
  405. [Fact]
  406. public void SortByDescending_ThenByDescending_should_generate_the_correct_sort()
  407. {
  408. var subject = CreateSubject()
  409. .SortByDescending(x => x.FirstName)
  410. .ThenByDescending(x => x.LastName);
  411. var expectedSort = BsonDocument.Parse("{$sort: {FirstName: -1, LastName: -1}}");
  412. AssertLast(subject, expectedSort);
  413. }
  414. [Fact]
  415. public void Unwind_with_expression_to_BsonDocument_should_generate_the_correct_unwind()
  416. {
  417. var subject = CreateSubject()
  418. .Unwind(x => x.Age);
  419. var expectedUnwind = BsonDocument.Parse("{$unwind: '$Age'}");
  420. AssertLast(subject, expectedUnwind);
  421. }
  422. [Fact]
  423. public void Unwind_with_expression_to_new_result_should_generate_the_correct_unwind()
  424. {
  425. var subject = CreateSubject()
  426. .Unwind<Person, BsonDocument>(x => x.Age);
  427. var expectedUnwind = BsonDocument.Parse("{$unwind: '$Age'}");
  428. AssertLast(subject, expectedUnwind);
  429. }
  430. [Fact]
  431. public void Unwind_should_generate_the_correct_unwind()
  432. {
  433. var subject = CreateSubject()
  434. .Unwind("Age");
  435. var expectedUnwind = BsonDocument.Parse("{$unwind: '$Age'}");
  436. AssertLast(subject, expectedUnwind);
  437. }
  438. [Fact]
  439. public void Unwind_to_new_result_with_a_serializer_should_generate_the_correct_unwind()
  440. {
  441. var subject = CreateSubject()
  442. .Unwind("Age", new AggregateUnwindOptions<BsonDocument> { ResultSerializer = BsonDocumentSerializer.Instance });
  443. var expectedUnwind = BsonDocument.Parse("{$unwind: '$Age'}");
  444. AssertLast(subject, expectedUnwind);
  445. }
  446. [Fact]
  447. public void Unwind_with_options_where_no_options_are_set()
  448. {
  449. var subject = CreateSubject()
  450. .Unwind("Age", new AggregateUnwindOptions<BsonDocument>());
  451. var expectedUnwind = BsonDocument.Parse("{$unwind: '$Age'}");
  452. AssertLast(subject, expectedUnwind);
  453. }
  454. [Fact]
  455. public void Unwind_with_options_with_preserveNullAndEmptyArrays_set()
  456. {
  457. var subject = CreateSubject()
  458. .Unwind("Age", new AggregateUnwindOptions<BsonDocument> { PreserveNullAndEmptyArrays = true });
  459. var expectedUnwind = BsonDocument.Parse("{$unwind: { path: '$Age', preserveNullAndEmptyArrays: true } }");
  460. AssertLast(subject, expectedUnwind);
  461. }
  462. [Fact]
  463. public void Unwind_with_options_with_includeArrayIndex_set()
  464. {
  465. var subject = CreateSubject()
  466. .Unwind("Age", new AggregateUnwindOptions<BsonDocument> { IncludeArrayIndex = "AgeIndex" });
  467. var expectedUnwind = BsonDocument.Parse("{$unwind: { path: '$Age', includeArrayIndex: 'AgeIndex' } }");
  468. AssertLast(subject, expectedUnwind);
  469. }
  470. [Fact]
  471. public void Unwind_with_options_with_includeArrayIndex_set_and_preserveNullAndEmptyArrays_set()
  472. {
  473. var subject = CreateSubject()
  474. .Unwind("Age", new AggregateUnwindOptions<BsonDocument>
  475. {
  476. IncludeArrayIndex = "AgeIndex",
  477. PreserveNullAndEmptyArrays = true
  478. });
  479. var expectedUnwind = BsonDocument.Parse("{$unwind: { path: '$Age', preserveNullAndEmptyArrays: true, includeArrayIndex: 'AgeIndex' } }");
  480. AssertLast(subject, expectedUnwind);
  481. }
  482. // private methods
  483. private void AssertLast<TDocument>(IAggregateFluent<TDocument> fluent, BsonDocument expectedLast)
  484. {
  485. var pipeline = new PipelineStagePipelineDefinition<Person, TDocument>(fluent.Stages);
  486. var renderedPipeline = pipeline.Render(BsonSerializer.SerializerRegistry.GetSerializer<Person>(), BsonSerializer.SerializerRegistry);
  487. var last = renderedPipeline.Documents.Last();
  488. Assert.Equal(expectedLast, last);
  489. }
  490. private IAggregateFluent<Person> CreateSubject(CancellationToken cancellationToken = default(CancellationToken))
  491. {
  492. var collection = CreateCollection<Person>();
  493. return new CollectionAggregateFluent<Person, Person>(null, collection, new EmptyPipelineDefinition<Person>(), new AggregateOptions());
  494. }
  495. private IMongoCollection<T> CreateCollection<T>(string collectionName = null)
  496. {
  497. var mockDatabase = new Mock<IMongoDatabase>();
  498. SetupDatabaseGetCollectionMethod<BsonDocument>(mockDatabase);
  499. var settings = new MongoCollectionSettings();
  500. var mockCollection = new Mock<IMongoCollection<T>>();
  501. mockCollection.SetupGet(c => c.CollectionNamespace).Returns(new CollectionNamespace(new DatabaseNamespace("test"), collectionName ?? typeof(T).Name));
  502. mockCollection.SetupGet(c => c.Database).Returns(mockDatabase.Object);
  503. mockCollection.SetupGet(c => c.DocumentSerializer).Returns(settings.SerializerRegistry.GetSerializer<T>());
  504. mockCollection.SetupGet(c => c.Settings).Returns(settings);
  505. return mockCollection.Object;
  506. }
  507. private void SetupDatabaseGetCollectionMethod<TDocument>(Mock<IMongoDatabase> mockDatabase)
  508. {
  509. mockDatabase
  510. .Setup(d => d.GetCollection<TDocument>(It.IsAny<string>(), It.IsAny<MongoCollectionSettings>()))
  511. .Returns((string collectionName, MongoCollectionSettings settings) =>
  512. {
  513. var mockCollection = new Mock<IMongoCollection<TDocument>>();
  514. mockCollection.SetupGet(c => c.CollectionNamespace).Returns(new CollectionNamespace(new DatabaseNamespace("test"), collectionName));
  515. return mockCollection.Object;
  516. });
  517. }
  518. private IAsyncCursor<Person> CreateCursor(params Person[] persons)
  519. {
  520. var firstBatch = persons ?? new Person[0];
  521. return new AsyncCursor<Person>(
  522. new Mock<IChannelSource>().Object,
  523. new CollectionNamespace(new DatabaseNamespace("foo"), "bar"),
  524. new BsonDocument(),
  525. firstBatch,
  526. 0,
  527. null,
  528. null,
  529. BsonSerializer.LookupSerializer<Person>(),
  530. new MessageEncoderSettings(),
  531. null);
  532. }
  533. // nested types
  534. public class Person
  535. {
  536. public string FirstName;
  537. public string LastName;
  538. public int Age;
  539. public PhoneNumber PhoneNumber;
  540. }
  541. public class PhoneNumber
  542. {
  543. public int AreaCode;
  544. public int Number;
  545. }
  546. public class NameMeaning
  547. {
  548. public string Name;
  549. public string Definition;
  550. }
  551. public class LookedUpPerson
  552. {
  553. public string FirstName;
  554. public string LastName;
  555. public int Age;
  556. public IEnumerable<NameMeaning> Meanings;
  557. }
  558. }
  559. }