PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/MongoDB.Driver.Tests/Linq/Translators/PredicateTranslatorTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 618 lines | 530 code | 74 blank | 14 comment | 36 complexity | 5099e7401a1ce0e01f0b9e770302ed7a MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using MongoDB.Bson;
  8. using MongoDB.Bson.Serialization;
  9. using MongoDB.Driver.Linq.Translators;
  10. using FluentAssertions;
  11. using NUnit.Framework;
  12. using System.Text.RegularExpressions;
  13. using MongoDB.Driver.Core;
  14. namespace MongoDB.Driver.Tests.Linq.Translators
  15. {
  16. [TestFixture]
  17. public class PredicateTranslatorTests : IntegrationTestBase
  18. {
  19. [Test]
  20. public void Any_without_a_predicate()
  21. {
  22. Assert(
  23. x => x.G.Any(),
  24. 2,
  25. "{G: {$ne: null, $not: {$size: 0}}}");
  26. }
  27. [Test]
  28. public void Any_with_a_predicate_on_documents()
  29. {
  30. Assert(
  31. x => x.G.Any(g => g.D == "Don't"),
  32. 1,
  33. "{\"G.D\": \"Don't\"}");
  34. Assert(
  35. x => x.G.Any(g => g.D == "Don't" && g.E.F == 33),
  36. 1,
  37. "{G: {$elemMatch: {D: \"Don't\", 'E.F': 33}}}");
  38. }
  39. [Test]
  40. public void Any_with_a_nested_Any()
  41. {
  42. Assert(
  43. x => x.G.Any(g => g.S.Any()),
  44. 1,
  45. "{G: {$elemMatch: {S: {$ne: null, $not: {$size: 0}}}}}");
  46. Assert(
  47. x => x.G.Any(g => g.S.Any(s => s.D == "Delilah")),
  48. 1,
  49. "{\"G.S.D\": \"Delilah\"}");
  50. }
  51. [Test]
  52. public void Any_with_a_not()
  53. {
  54. Assert(
  55. x => x.G.Any(g => !g.S.Any()),
  56. 2,
  57. "{G: {$elemMatch: {$nor: [{S: {$ne: null, $not: {$size: 0}}}]}}}");
  58. Assert(
  59. x => x.G.Any(g => !g.S.Any(s => s.D == "Delilah")),
  60. 1,
  61. "{\"G.S.D\": {$ne: \"Delilah\"}}}");
  62. }
  63. [Test]
  64. public void Any_with_a_predicate_on_scalars_legacy()
  65. {
  66. Assert(
  67. x => x.M.Any(m => m > 5),
  68. 1,
  69. "{M: {$gt: 5}}");
  70. Assert(
  71. x => x.M.Any(m => m > 2 && m < 6),
  72. 2,
  73. "{M: {$elemMatch: {$gt: 2, $lt: 6}}}");
  74. }
  75. [Test]
  76. [RequiresServer(MinimumVersion = "2.6.0")]
  77. public void Any_with_a_predicate_on_scalars()
  78. {
  79. Assert(
  80. x => x.C.E.I.Any(i => i.StartsWith("ick")),
  81. 1,
  82. "{\"C.E.I\": /^ick/s}");
  83. // this isn't a legal query, as in, there isn't any
  84. // way to render this legally for the server...
  85. //Assert(
  86. // x => x.C.E.I.Any(i => i.StartsWith("ick") && i == "Jack"),
  87. // 1,
  88. // new BsonDocument(
  89. // "C.E.I",
  90. // new BsonDocument(
  91. // "$elemMatch",
  92. // new BsonDocument
  93. // {
  94. // { "$regex", new BsonRegularExpression("^ick", "s") },
  95. // { "$eq", "Jack" }
  96. // })));
  97. }
  98. [Test]
  99. public void LocalIListContains()
  100. {
  101. IList<int> local = new[] { 10, 20, 30 };
  102. Assert(
  103. x => local.Contains(x.Id),
  104. 2,
  105. "{_id: {$in: [10, 20, 30]}}");
  106. }
  107. [Test]
  108. public void LocalListContains()
  109. {
  110. var local = new List<int> { 10, 20, 30 };
  111. Assert(
  112. x => local.Contains(x.Id),
  113. 2,
  114. "{_id: {$in: [10, 20, 30]}}");
  115. }
  116. [Test]
  117. public void LocalArrayContains()
  118. {
  119. var local = new[] { 10, 20, 30 };
  120. Assert(
  121. x => local.Contains(x.Id),
  122. 2,
  123. "{_id: {$in: [10, 20, 30]}}");
  124. }
  125. [Test]
  126. public void ArrayLengthEquals()
  127. {
  128. Assert(
  129. x => x.M.Length == 3,
  130. 2,
  131. "{M: {$size: 3}}");
  132. Assert(
  133. x => 3 == x.M.Length,
  134. 2,
  135. "{M: {$size: 3}}");
  136. }
  137. [Test]
  138. public void ArrayLengthNotEquals()
  139. {
  140. Assert(
  141. x => x.M.Length != 3,
  142. 0,
  143. "{M: {$not: {$size: 3}}}");
  144. }
  145. [Test]
  146. public void NotArrayLengthEquals()
  147. {
  148. Assert(
  149. x => !(x.M.Length == 3),
  150. 0,
  151. "{M: {$not: {$size: 3}}}");
  152. }
  153. [Test]
  154. public void NotArrayLengthNotEquals()
  155. {
  156. Assert(
  157. x => !(x.M.Length != 3),
  158. 2,
  159. "{M: {$size: 3}}");
  160. }
  161. [Test]
  162. public void ArrayPositionEquals()
  163. {
  164. Assert(
  165. x => x.M[1] == 4,
  166. 1,
  167. "{'M.1': 4}");
  168. }
  169. [Test]
  170. public void ArrayPositionNotEquals()
  171. {
  172. Assert(
  173. x => x.M[1] != 4,
  174. 1,
  175. "{'M.1': {$ne: 4}}");
  176. }
  177. [Test]
  178. public void ArrayPositionModEqual()
  179. {
  180. Assert(
  181. x => x.M[1] % 2 == 0,
  182. 1,
  183. "{'M.1': {$mod: [NumberLong(2), NumberLong(0)]}}");
  184. }
  185. [Test]
  186. public void ArrayPositionModNotEqual()
  187. {
  188. Assert(
  189. x => x.M[1] % 3 != 2,
  190. 1,
  191. "{'M.1': {$not: {$mod: [NumberLong(3), NumberLong(2)]}}}");
  192. }
  193. [Test]
  194. public void Boolean()
  195. {
  196. Assert(
  197. x => x.K,
  198. 1,
  199. "{K: true}");
  200. }
  201. [Test]
  202. public void BooleanEqualsTrue()
  203. {
  204. Assert(
  205. x => x.K == true,
  206. 1,
  207. "{K: true}");
  208. }
  209. [Test]
  210. public void BooleanEqualsMethod()
  211. {
  212. Assert(
  213. x => x.K.Equals(true),
  214. 1,
  215. "{K: true}");
  216. }
  217. [Test]
  218. public void BooleanEqualsFalse()
  219. {
  220. Assert(
  221. x => x.K == false,
  222. 1,
  223. "{K: false}");
  224. }
  225. [Test]
  226. public void BooleanNotEqualsTrue()
  227. {
  228. Assert(
  229. x => x.K != true,
  230. 1,
  231. "{K: {$ne: true}}");
  232. }
  233. [Test]
  234. public void BooleanNotEqualsFalse()
  235. {
  236. Assert(
  237. x => x.K != false,
  238. 1,
  239. "{K: {$ne: false}}");
  240. }
  241. [Test]
  242. public void NotBoolean()
  243. {
  244. Assert(
  245. x => !x.K,
  246. 1,
  247. "{K: {$ne: true}}");
  248. }
  249. [Test]
  250. public void ClassEquals()
  251. {
  252. Assert(
  253. x => x.C == new C { D = "Dexter" },
  254. 0,
  255. "{C: {D: 'Dexter', E: null, S: null}}");
  256. }
  257. [Test]
  258. public void ClassEqualsMethod()
  259. {
  260. Assert(
  261. x => x.C.Equals(new C { D = "Dexter" }),
  262. 0,
  263. "{C: {D: 'Dexter', E: null, S: null}}");
  264. }
  265. [Test]
  266. public void ClassNotEquals()
  267. {
  268. Assert(
  269. x => x.C != new C { D = "Dexter" },
  270. 2,
  271. "{C: {$ne: {D: 'Dexter', E: null, S: null}}}");
  272. }
  273. [Test]
  274. public void ClassMemberEquals()
  275. {
  276. Assert(
  277. x => x.C.D == "Dexter",
  278. 1,
  279. "{'C.D': 'Dexter'}");
  280. }
  281. [Test]
  282. public void ClassMemberNotEquals()
  283. {
  284. Assert(
  285. x => x.C.D != "Dexter",
  286. 1,
  287. "{'C.D': {$ne: 'Dexter'}}");
  288. }
  289. [Test]
  290. public void CompareTo_equal()
  291. {
  292. Assert(
  293. x => x.A.CompareTo("Amazing") == 0,
  294. 1,
  295. "{'A': 'Amazing' }");
  296. }
  297. [Test]
  298. public void CompareTo_greater_than()
  299. {
  300. Assert(
  301. x => x.A.CompareTo("Around") > 0,
  302. 1,
  303. "{'A': { $gt: 'Around' } }");
  304. }
  305. [Test]
  306. public void CompareTo_greater_than_or_equal()
  307. {
  308. Assert(
  309. x => x.A.CompareTo("Around") >= 0,
  310. 1,
  311. "{'A': { $gte: 'Around' } }");
  312. }
  313. [Test]
  314. public void CompareTo_less_than()
  315. {
  316. Assert(
  317. x => x.A.CompareTo("Around") < 0,
  318. 1,
  319. "{'A': { $lt: 'Around' } }");
  320. }
  321. [Test]
  322. public void CompareTo_less_than_or_equal()
  323. {
  324. Assert(
  325. x => x.A.CompareTo("Around") <= 0,
  326. 1,
  327. "{'A': { $lte: 'Around' } }");
  328. }
  329. [Test]
  330. public void CompareTo_not_equal()
  331. {
  332. Assert(
  333. x => x.A.CompareTo("Amazing") != 0,
  334. 1,
  335. "{'A': { $ne: 'Amazing' } }");
  336. }
  337. [Test]
  338. public void DictionaryIndexer()
  339. {
  340. Assert(
  341. x => x.T["one"] == 1,
  342. 1,
  343. "{'T.one': 1}");
  344. }
  345. [Test]
  346. public void EnumerableCount()
  347. {
  348. Assert(
  349. x => x.G.Count() == 2,
  350. 2,
  351. "{'G': {$size: 2}}");
  352. }
  353. [Test]
  354. public void EnumerableElementAtEquals()
  355. {
  356. Assert(
  357. x => x.G.ElementAt(1).D == "Dolphin",
  358. 1,
  359. "{'G.1.D': 'Dolphin'}");
  360. }
  361. [Test]
  362. public void Equals_with_byte_based_enum()
  363. {
  364. Assert(
  365. x => x.Q == Q.One,
  366. 1,
  367. "{'Q': 1}");
  368. }
  369. [Test]
  370. public void Equals_with_nullable_date_time()
  371. {
  372. Assert(
  373. x => x.R.HasValue && x.R.Value > DateTime.MinValue,
  374. 1,
  375. "{'R': { $ne: null, $gt: ISODate('0001-01-01T00:00:00Z') } }");
  376. }
  377. [Test]
  378. public void HashSetCount()
  379. {
  380. Assert(
  381. x => x.L.Count == 3,
  382. 2,
  383. "{'L': {$size: 3}}");
  384. }
  385. [Test]
  386. public void ListCount()
  387. {
  388. Assert(
  389. x => x.O.Count == 3,
  390. 2,
  391. "{'O': {$size: 3}}");
  392. }
  393. [Test]
  394. public void ListSubEquals()
  395. {
  396. Assert(
  397. x => x.O[2] == 30,
  398. 1,
  399. "{'O.2': NumberLong(30)}");
  400. }
  401. [Test]
  402. public void RegexInstanceMatch()
  403. {
  404. var regex = new Regex("^Awe");
  405. Assert(
  406. x => regex.IsMatch(x.A),
  407. 1,
  408. "{A: /^Awe/}");
  409. }
  410. [Test]
  411. public void RegexStaticMatch()
  412. {
  413. Assert(
  414. x => Regex.IsMatch(x.A, "^Awe"),
  415. 1,
  416. "{A: /^Awe/}");
  417. }
  418. [Test]
  419. public void RegexStaticMatch_with_options()
  420. {
  421. Assert(
  422. x => Regex.IsMatch(x.A, "^Awe", RegexOptions.IgnoreCase),
  423. 1,
  424. "{A: /^Awe/i}");
  425. }
  426. [Test]
  427. public void StringContains()
  428. {
  429. Assert(
  430. x => x.A.Contains("some"),
  431. 1,
  432. "{A: /some/s}");
  433. }
  434. [Test]
  435. public void StringContains_with_dot()
  436. {
  437. Assert(
  438. x => x.A.Contains("."),
  439. 0,
  440. "{A: /\\./s}");
  441. }
  442. [Test]
  443. public void StringNotContains()
  444. {
  445. Assert(
  446. x => !x.A.Contains("some"),
  447. 1,
  448. "{A: {$not: /some/s}}");
  449. }
  450. [Test]
  451. public void StringEndsWith()
  452. {
  453. Assert(
  454. x => x.A.EndsWith("some"),
  455. 1,
  456. "{A: /some$/s}");
  457. }
  458. [Test]
  459. public void StringStartsWith()
  460. {
  461. Assert(
  462. x => x.A.StartsWith("some"),
  463. 0,
  464. "{A: /^some/s}");
  465. }
  466. [Test]
  467. public void StringEquals()
  468. {
  469. Assert(
  470. x => x.A == "Awesome",
  471. 1,
  472. "{A: 'Awesome'}");
  473. }
  474. [Test]
  475. public void StringEqualsMethod()
  476. {
  477. Assert(
  478. x => x.A.Equals("Awesome"),
  479. 1,
  480. "{A: 'Awesome'}");
  481. }
  482. [Test]
  483. public void NotStringEqualsMethod()
  484. {
  485. Assert(
  486. x => !x.A.Equals("Awesome"),
  487. 1,
  488. "{A: {$ne: 'Awesome'}}");
  489. }
  490. [Test]
  491. public void String_IsNullOrEmpty()
  492. {
  493. Assert(
  494. x => string.IsNullOrEmpty(x.A),
  495. 0,
  496. "{A: { $in: [null, ''] } }");
  497. }
  498. [Test]
  499. public void Not_String_IsNullOrEmpty()
  500. {
  501. Assert(
  502. x => !string.IsNullOrEmpty(x.A),
  503. 2,
  504. "{A: { $nin: [null, ''] } }");
  505. }
  506. [Test]
  507. public async Task Binding_through_an_unnecessary_conversion()
  508. {
  509. var root = await Find(_collection, 10);
  510. root.Should().NotBeNull();
  511. root.A.Should().Be("Awesome");
  512. }
  513. [Test]
  514. public async Task Binding_through_an_unnecessary_conversion_with_a_builder()
  515. {
  516. var root = await FindWithBuilder(_collection, 10);
  517. root.Should().NotBeNull();
  518. root.A.Should().Be("Awesome");
  519. }
  520. private Task<T> Find<T>(IMongoCollection<T> collection, int id) where T : IRoot
  521. {
  522. return collection.Find(x => x.Id == id).FirstOrDefaultAsync();
  523. }
  524. private Task<T> FindWithBuilder<T>(IMongoCollection<T> collection, int id) where T : IRoot
  525. {
  526. return collection.Find(Builders<T>.Filter.Eq(x => x.Id, id)).FirstOrDefaultAsync();
  527. }
  528. public void Assert(Expression<Func<Root, bool>> filter, int expectedCount, string expectedFilter)
  529. {
  530. Assert(filter, expectedCount, BsonDocument.Parse(expectedFilter));
  531. }
  532. public void Assert(Expression<Func<Root, bool>> filter, int expectedCount, BsonDocument expectedFilter)
  533. {
  534. var serializer = BsonSerializer.SerializerRegistry.GetSerializer<Root>();
  535. var filterDocument = PredicateTranslator.Translate(filter, serializer, BsonSerializer.SerializerRegistry);
  536. using (var cursor = _collection.FindAsync(filterDocument).GetAwaiter().GetResult())
  537. {
  538. var list = cursor.ToListAsync().GetAwaiter().GetResult();
  539. filterDocument.Should().Be(expectedFilter);
  540. list.Count.Should().Be(expectedCount);
  541. }
  542. }
  543. }
  544. }