1+ #if NET10_0_OR_GREATER
2+ using System ;
3+ using System . Linq ;
4+ using System . Linq . Expressions ;
5+ using NUnit . Framework ;
6+ using Xtensive . Orm . Tests . ObjectModel ;
7+ using Xtensive . Orm . Tests . ObjectModel . ChinookDO ;
8+
9+ namespace Xtensive . Orm . Tests . Linq
10+ {
11+
12+ [ Category ( "Linq" ) ]
13+ [ TestFixture ( Description = "Test cases when System.MemoryExtensions are applied instead of more general versions of methods from EnumerableExtensions" ) ]
14+ public class MemoryExtensionsTest : ChinookDOModelTest
15+ {
16+ private int [ ] existingGenreIds ;
17+ private string [ ] existingGenreNames ;
18+
19+ protected override void CheckRequirements ( )
20+ {
21+ Expression < Func < bool > > testExpr = ( ) => new int [ ] { 1 , 2 } . Contains ( 2 ) ;
22+ if ( testExpr . Body is MethodCallExpression mc && mc . Method . DeclaringType == typeof ( MemoryExtensions ) ) {
23+ // in C# 14+ the expression will use implicit cast to ReadOnlySpan<T>
24+ // and use Contains extension method from MemoryExtensions.
25+ // In previous versions of language they use IEnumerable<int>.Contains() extension method.
26+ // What's funny is that in code you cannot create ReadOnlySpans expressions, directly or via .AsSpan() :-)
27+ return ;
28+ }
29+ throw new IgnoreException ( "Wrong version of language. Test is inapplicable." ) ;
30+ }
31+
32+ public override void SetUp ( )
33+ {
34+ base . SetUp ( ) ;
35+ existingGenreIds = Genres . Select ( g=> g . GenreId ) . OrderBy ( id => id ) . ToArray ( ) ;
36+ existingGenreNames = Genres . Select ( g => g . Name ) . ToArray ( ) ;
37+ }
38+
39+ #region Contains over ReadOnlySpan<int>
40+
41+ [ Test ]
42+ public void IntArrayContainsInAllTest ( )
43+ {
44+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
45+
46+ var query = Session . Query . All < Genre > ( )
47+ . All ( g => existingIds . Contains ( g . GenreId ) ) ;
48+ Assert . That ( query , Is . False ) ;
49+
50+ query = Session . Query . All < Genre > ( )
51+ . All ( g => existingGenreIds . Contains ( g . GenreId ) ) ;
52+ Assert . That ( query , Is . True ) ;
53+
54+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
55+ }
56+
57+ [ Test ]
58+ public void IntArrayContainsInAnyTest ( )
59+ {
60+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
61+
62+ var query = Session . Query . All < Genre > ( )
63+ . Any ( g => existingIds . Contains ( g . GenreId ) ) ;
64+ Assert . That ( query , Is . True ) ;
65+
66+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
67+ query = Session . Query . All < Genre > ( ) . Any ( g => inexistentIds . Contains ( g . GenreId ) ) ;
68+ Assert . That ( query , Is . False ) ;
69+ }
70+
71+ [ Test ]
72+ public void IntArrayContainsInCountTest ( )
73+ {
74+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
75+ var query = Session . Query . All < Genre > ( )
76+ . Count ( g => existingIds . Contains ( g . GenreId ) ) ;
77+ Assert . That ( query , Is . EqualTo ( existingIds . Length ) ) ;
78+
79+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
80+ query = Session . Query . All < Genre > ( )
81+ . Count ( g => inexistentIds . Contains ( g . GenreId ) ) ;
82+ Assert . That ( query , Is . EqualTo ( 0 ) ) ;
83+ }
84+
85+ [ Test ]
86+ public void IntArrayContainsInGroupByTest ( )
87+ {
88+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
89+ var query = Session . Query . All < Genre > ( )
90+ . GroupBy ( g => existingIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
91+ Assert . That ( query . Length , Is . EqualTo ( 2 ) ) ;
92+ var firstGroup = query [ 0 ] ;
93+ Assert . That ( firstGroup . Key , Is . False ) ;
94+ Assert . That ( firstGroup . Count ( ) , Is . EqualTo ( existingGenreIds . Length - existingIds . Length ) ) ;
95+
96+ var secondGroup = query [ 1 ] ;
97+ Assert . That ( secondGroup . Key , Is . True ) ;
98+ Assert . That ( secondGroup . Count ( ) , Is . EqualTo ( existingIds . Length ) ) ;
99+
100+
101+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
102+ query = Session . Query . All < Genre > ( )
103+ . GroupBy ( g => inexistentIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
104+ Assert . That ( query . Length , Is . EqualTo ( 1 ) ) ;
105+ firstGroup = query [ 0 ] ;
106+ Assert . That ( firstGroup . Key , Is . False ) ;
107+ Assert . That ( firstGroup . Count ( ) , Is . EqualTo ( existingGenreIds . Length ) ) ;
108+ }
109+
110+ [ Test ]
111+ public void IntArrayContainsInOrderByTest ( )
112+ {
113+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
114+ var genres = Session . Query . All < Genre > ( )
115+ . OrderBy ( g => existingIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
116+
117+ Assert . That ( genres . Take ( existingGenreIds . Length - existingIds . Length ) . All ( g => ! existingIds . Contains ( g . GenreId ) ) , Is . True ) ;
118+ Assert . That ( genres . Skip ( existingGenreIds . Length - existingIds . Length ) . All ( g => existingIds . Contains ( g . GenreId ) ) , Is . True ) ;
119+
120+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
121+ genres = Session . Query . All < Genre > ( )
122+ . OrderBy ( g => inexistentIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
123+ Assert . That ( genres . All ( g => ! inexistentIds . Contains ( g . GenreId ) ) , Is . True ) ;
124+ }
125+
126+ [ Test ]
127+ public void IntArrayContainsInSelectTest ( )
128+ {
129+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
130+
131+ var queryResult = Session . Query . All < Genre > ( )
132+ . Select ( g => existingIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
133+ Assert . That ( queryResult . Length , Is . EqualTo ( existingGenreIds . Length ) ) ;
134+ Assert . That ( queryResult . Count ( b => b == true ) , Is . EqualTo ( existingIds . Length ) ) ;
135+
136+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
137+ queryResult = Session . Query . All < Genre > ( )
138+ . Select ( g => inexistentIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
139+ Assert . That ( queryResult . Length , Is . EqualTo ( existingGenreIds . Length ) ) ;
140+ Assert . That ( queryResult . Count ( b => b == true ) , Is . EqualTo ( 0 ) ) ;
141+ }
142+
143+ [ Test ]
144+ public void IntArrayContainsInWhereTest ( )
145+ {
146+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
147+ var genres = Session . Query . All < Genre > ( )
148+ . Where ( g => existingIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
149+ Assert . That ( genres . Length , Is . EqualTo ( existingIds . Length ) ) ;
150+ Assert . That ( genres . All ( g => existingIds . Contains ( g . GenreId ) ) ) ;
151+
152+
153+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
154+ genres = Session . Query . All < Genre > ( )
155+ . Where ( g => inexistentIds . Contains ( g . GenreId ) ) . ToArray ( ) ;
156+
157+ Assert . That ( genres . Length , Is . EqualTo ( 0 ) ) ;
158+ Assert . That ( genres . All ( g => ! existingIds . Contains ( g . GenreId ) ) ) ;
159+ }
160+
161+ [ Test ]
162+ public void IntArrayContainsInFirstTest ( )
163+ {
164+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
165+ var genre = Session . Query . All < Genre > ( )
166+ . First ( g => existingIds . Contains ( g . GenreId ) ) ;
167+ Assert . That ( genre . GenreId , Is . EqualTo ( existingIds [ 0 ] ) ) ;
168+ }
169+
170+ [ Test ]
171+ public void IntArrayContainsInFirstOrDefaultTest ( )
172+ {
173+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
174+ var genre = Session . Query . All < Genre > ( )
175+ . FirstOrDefault ( g => existingIds . Contains ( g . GenreId ) ) ;
176+
177+ Assert . That ( genre , Is . Not . Null ) ;
178+ Assert . That ( genre . GenreId , Is . EqualTo ( existingIds [ 0 ] ) ) ;
179+
180+
181+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 6 ) . ToArray ( ) ;
182+ genre = Session . Query . All < Genre > ( )
183+ . FirstOrDefault ( g => inexistentIds . Contains ( g . GenreId ) ) ;
184+ Assert . That ( genre , Is . Null ) ;
185+ }
186+
187+ [ Test ]
188+ public void IntArrayContainsInSingleTest2 ( )
189+ {
190+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 1 ) . ToArray ( ) ;
191+ var genre = Session . Query . All < Genre > ( )
192+ . Single ( g => existingIds . Contains ( g . GenreId ) ) ;
193+
194+ Assert . That ( genre , Is . Not . Null ) ;
195+ Assert . That ( genre . GenreId , Is . EqualTo ( existingIds [ 0 ] ) ) ;
196+ }
197+
198+ [ Test ]
199+ public void IntArrayContainsInSingleOrDefaultTest2 ( )
200+ {
201+ var existingIds = existingGenreIds . Skip ( 5 ) . Take ( 1 ) . ToArray ( ) ;
202+ var genre = Session . Query . All < Genre > ( )
203+ . SingleOrDefault ( g => existingIds . Contains ( g . GenreId ) ) ;
204+
205+ Assert . That ( genre , Is . Not . Null ) ;
206+ Assert . That ( genre . GenreId , Is . EqualTo ( existingIds [ 0 ] ) ) ;
207+
208+ var inexistentIds = Enumerable . Range ( existingGenreIds [ ^ 1 ] + 10 , 1 ) . ToArray ( ) ;
209+
210+ genre = Session . Query . All < Genre > ( )
211+ . SingleOrDefault ( g => inexistentIds . Contains ( g . GenreId ) ) ;
212+
213+ Assert . That ( genre , Is . Null ) ;
214+ }
215+
216+ #endregion
217+
218+ #region Contains over ReadOnlySpan<string>
219+
220+ [ Test ]
221+ public void StringArrayContainsInAllTest ( )
222+ {
223+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
224+
225+ var query = Session . Query . All < Genre > ( )
226+ . All ( g => existingNames . Contains ( g . Name ) ) ;
227+ Assert . That ( query , Is . False ) ;
228+
229+ query = Session . Query . All < Genre > ( )
230+ . All ( g => existingGenreNames . Contains ( g . Name ) ) ;
231+ Assert . That ( query , Is . True ) ;
232+ }
233+
234+ [ Test ]
235+ public void StringArrayContainsInAnyTest ( )
236+ {
237+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
238+
239+ var query = Session . Query . All < Genre > ( )
240+ . Any ( g => existingNames . Contains ( g . Name ) ) ;
241+ Assert . That ( query , Is . True ) ;
242+
243+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
244+ query = Session . Query . All < Genre > ( ) . Any ( g => inexistentNames . Contains ( g . Name ) ) ;
245+ Assert . That ( query , Is . False ) ;
246+ }
247+
248+ [ Test ]
249+ public void StringArrayContainsInCountTest ( )
250+ {
251+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
252+ var query = Session . Query . All < Genre > ( )
253+ . Count ( g => existingNames . Contains ( g . Name ) ) ;
254+ Assert . That ( query , Is . EqualTo ( existingNames . Length ) ) ;
255+
256+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
257+ query = Session . Query . All < Genre > ( )
258+ . Count ( g => inexistentNames . Contains ( g . Name ) ) ;
259+ Assert . That ( query , Is . EqualTo ( 0 ) ) ;
260+ }
261+
262+ [ Test ]
263+ public void StringArrayContainsInGroupByTest ( )
264+ {
265+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
266+ var query = Session . Query . All < Genre > ( )
267+ . GroupBy ( g => existingNames . Contains ( g . Name ) ) . ToArray ( ) ;
268+ Assert . That ( query . Length , Is . EqualTo ( 2 ) ) ;
269+ var firstGroup = query [ 0 ] ;
270+ Assert . That ( firstGroup . Key , Is . False ) ;
271+ Assert . That ( firstGroup . Count ( ) , Is . EqualTo ( existingGenreNames . Length - existingNames . Length ) ) ;
272+
273+ var secondGroup = query [ 1 ] ;
274+ Assert . That ( secondGroup . Key , Is . True ) ;
275+ Assert . That ( secondGroup . Count ( ) , Is . EqualTo ( existingNames . Length ) ) ;
276+
277+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
278+ query = Session . Query . All < Genre > ( )
279+ . GroupBy ( g => inexistentNames . Contains ( g . Name ) ) . ToArray ( ) ;
280+ Assert . That ( query . Length , Is . EqualTo ( 1 ) ) ;
281+ firstGroup = query [ 0 ] ;
282+ Assert . That ( firstGroup . Key , Is . False ) ;
283+ Assert . That ( firstGroup . Count ( ) , Is . EqualTo ( existingGenreNames . Length ) ) ;
284+ }
285+
286+ [ Test ]
287+ public void StringArrayContainsInOrderByTest ( )
288+ {
289+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
290+ var genres = Session . Query . All < Genre > ( )
291+ . OrderBy ( g => existingNames . Contains ( g . Name ) ) . ToArray ( ) ;
292+
293+ Assert . That ( genres . Take ( existingGenreNames . Length - existingNames . Length ) . All ( g => ! existingNames . Contains ( g . Name ) ) , Is . True ) ;
294+ Assert . That ( genres . Skip ( existingGenreNames . Length - existingNames . Length ) . All ( g => existingNames . Contains ( g . Name ) ) , Is . True ) ;
295+
296+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
297+ genres = Session . Query . All < Genre > ( )
298+ . OrderBy ( g => inexistentNames . Contains ( g . Name ) ) . ToArray ( ) ;
299+ Assert . That ( genres . All ( g => ! inexistentNames . Contains ( g . Name ) ) , Is . True ) ;
300+ }
301+
302+ [ Test ]
303+ public void StringArrayContainsInSelectTest ( )
304+ {
305+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
306+
307+ var queryResult = Session . Query . All < Genre > ( )
308+ . Select ( g => existingNames . Contains ( g . Name ) ) . ToArray ( ) ;
309+ Assert . That ( queryResult . Length , Is . EqualTo ( existingGenreNames . Length ) ) ;
310+ Assert . That ( queryResult . Count ( b => b == true ) , Is . EqualTo ( existingNames . Length ) ) ;
311+
312+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
313+ queryResult = Session . Query . All < Genre > ( )
314+ . Select ( g => inexistentNames . Contains ( g . Name ) ) . ToArray ( ) ;
315+ Assert . That ( queryResult . Length , Is . EqualTo ( existingGenreNames . Length ) ) ;
316+ Assert . That ( queryResult . Count ( b => b == true ) , Is . EqualTo ( 0 ) ) ;
317+ }
318+
319+ [ Test ]
320+ public void StringArrayContainsInWhereTest ( )
321+ {
322+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
323+ var genres = Session . Query . All < Genre > ( )
324+ . Where ( g => existingNames . Contains ( g . Name ) ) . ToArray ( ) ;
325+ Assert . That ( genres . Length , Is . EqualTo ( existingNames . Length ) ) ;
326+ Assert . That ( genres . All ( g => existingNames . Contains ( g . Name ) ) ) ;
327+
328+
329+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
330+ genres = Session . Query . All < Genre > ( )
331+ . Where ( g => inexistentNames . Contains ( g . Name ) ) . ToArray ( ) ;
332+
333+ Assert . That ( genres . Length , Is . EqualTo ( 0 ) ) ;
334+ Assert . That ( genres . All ( g => ! existingNames . Contains ( g . Name ) ) ) ;
335+ }
336+
337+ [ Test ]
338+ public void StringArrayContainsInFirstTest ( )
339+ {
340+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
341+ var genre = Session . Query . All < Genre > ( )
342+ . First ( g => existingNames . Contains ( g . Name ) ) ;
343+ Assert . That ( genre . Name , Is . EqualTo ( existingNames [ 0 ] ) ) ;
344+ }
345+
346+ [ Test ]
347+ public void StringArrayContainsInFirstOrDefaultTest ( )
348+ {
349+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 5 ) . ToArray ( ) ;
350+ var genre = Session . Query . All < Genre > ( )
351+ . FirstOrDefault ( g => existingNames . Contains ( g . Name ) ) ;
352+
353+ Assert . That ( genre , Is . Not . Null ) ;
354+ Assert . That ( genre . Name , Is . EqualTo ( existingNames [ 0 ] ) ) ;
355+
356+
357+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" , "oeoeoeoeoe" , "qqkkqqkk" , "pweoirsl" , "eienhjg" , "rrooroor" } ;
358+ genre = Session . Query . All < Genre > ( )
359+ . FirstOrDefault ( g => inexistentNames . Contains ( g . Name ) ) ;
360+ Assert . That ( genre , Is . Null ) ;
361+ }
362+
363+ [ Test ]
364+ public void StringArrayContainsInSingleTest2 ( )
365+ {
366+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 1 ) . ToArray ( ) ;
367+ var genre = Session . Query . All < Genre > ( )
368+ . Single ( g => existingNames . Contains ( g . Name ) ) ;
369+
370+ Assert . That ( genre , Is . Not . Null ) ;
371+ Assert . That ( genre . Name , Is . EqualTo ( existingNames [ 0 ] ) ) ;
372+ }
373+
374+ [ Test ]
375+ public void StringArrayContainsInSingleOrDefaultTest2 ( )
376+ {
377+ var existingNames = existingGenreNames . Skip ( 5 ) . Take ( 1 ) . ToArray ( ) ;
378+ var genre = Session . Query . All < Genre > ( )
379+ . SingleOrDefault ( g => existingNames . Contains ( g . Name ) ) ;
380+
381+ Assert . That ( genre , Is . Not . Null ) ;
382+ Assert . That ( genre . Name , Is . EqualTo ( existingNames [ 0 ] ) ) ;
383+
384+ var inexistentNames = new string [ ] { "bbbaaarrrvvv" } ;
385+
386+ genre = Session . Query . All < Genre > ( )
387+ . SingleOrDefault ( g => inexistentNames . Contains ( g . Name ) ) ;
388+
389+ Assert . That ( genre , Is . Null ) ;
390+ }
391+
392+ #endregion
393+ }
394+ }
395+ #endif
0 commit comments