Skip to content

Commit e52b523

Browse files
committed
Fix Slice implentation and add Unit tests
1 parent d294b38 commit e52b523

File tree

2 files changed

+198
-16
lines changed

2 files changed

+198
-16
lines changed

Cql/CoreTests/PrimitiveTests.cs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3539,5 +3539,190 @@ public void QuantityToString()
35393539
var s = ops.ConvertQuantityToString(new CqlQuantity(125, "cm"));
35403540
s.Should().Be("125 'cm'");
35413541
}
3542+
3543+
#region Slice tests
3544+
3545+
/* Refer http://cql.hl7.org/09-b-cqlreference.html for operation details on Skip, Tail and Take cql operators
3546+
* These CQL operators uses Slice semantics from http://cql.hl7.org/04-logicalspecification.html#slice
3547+
*/
3548+
3549+
[TestCategory("SliceTests")]
3550+
[TestMethod]
3551+
public void Skip2()
3552+
{
3553+
//The Skip operator returns the elements in the list, skipping the first number elements.
3554+
//define "Skip2": Skip({ 1, 2, 3, 4, 5 }, 2) // { 3, 4, 5 }
3555+
var rtx = GetNewContext();
3556+
var inputList = new List<int> { 1, 2, 3, 4, 5 };
3557+
var expectedList = new List<int> { 3, 4, 5 };
3558+
var slicedList = rtx.Operators.Slice(inputList, 2, null);
3559+
Assert.IsNotNull(slicedList);
3560+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3561+
}
3562+
3563+
[TestCategory("SliceTests")]
3564+
[TestMethod]
3565+
public void SkipNull()
3566+
{
3567+
//If the number of elements is null, the result is the entire list, no elements are skipped.
3568+
//define "SkipNull": Skip({ 1, 3, 5 }, null) // { 1, 3, 5 }
3569+
var rtx = GetNewContext();
3570+
var inputList = new List<int> { 1, 3, 5 };
3571+
var expectedList = new List<int> { 1, 3, 5 };
3572+
var slicedList = rtx.Operators.Slice(inputList, null, null);
3573+
Assert.IsNotNull(slicedList);
3574+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3575+
}
3576+
3577+
[TestCategory("SliceTests")]
3578+
[TestMethod]
3579+
public void SkipEmpty()
3580+
{
3581+
//If the number of elements is less than zero, the result is an empty list.
3582+
//define "SkipEmpty": Skip({ 1, 3, 5 }, -1) // { }
3583+
var rtx = GetNewContext();
3584+
var inputList = new List<int> { 1, 3, 5 };
3585+
var expectedList = new List<int> { };
3586+
var slicedList = rtx.Operators.Slice(inputList, -1, null);
3587+
Assert.IsNotNull(slicedList);
3588+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3589+
}
3590+
3591+
[TestCategory("SliceTests")]
3592+
[TestMethod]
3593+
public void SkipIsNull()
3594+
{
3595+
//If the source list is null, the result is null.
3596+
//define "SkipIsNull": Skip(null, 2)
3597+
var rtx = GetNewContext();
3598+
var inputList = null as List<int>;
3599+
var expectedList = null as List<int>;
3600+
var slicedList = rtx.Operators.Slice(inputList, 2, null);
3601+
Assert.IsNull(slicedList);
3602+
}
3603+
3604+
[TestCategory("SliceTests")]
3605+
[TestMethod]
3606+
public void Tail234()
3607+
{
3608+
//The Tail operator returns all but the first element from the given list.
3609+
//define "Tail234": Tail({ 1, 2, 3, 4 }) // { 2, 3, 4 }
3610+
var rtx = GetNewContext();
3611+
var inputList = new List<int> { 1, 2, 3, 4 };
3612+
var expectedList = new List<int> { 2, 3, 4 };
3613+
var slicedList = rtx.Operators.Slice(inputList, 1, null);
3614+
Assert.IsNotNull(slicedList);
3615+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3616+
}
3617+
3618+
[TestCategory("SliceTests")]
3619+
[TestMethod]
3620+
public void TailEmpty()
3621+
{
3622+
//If the list is empty, the result is empty.
3623+
//define "TailEmpty": Tail({ }) // { }
3624+
var rtx = GetNewContext();
3625+
var inputList = new List<int> { };
3626+
var expectedList = new List<int> { };
3627+
var slicedList = rtx.Operators.Slice(inputList, 1, null);
3628+
Assert.IsNotNull(slicedList);
3629+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3630+
}
3631+
3632+
[TestCategory("SliceTests")]
3633+
[TestMethod]
3634+
public void TailIsNull()
3635+
{
3636+
//If the source list is null, the result is null.
3637+
//define "TailIsNull": Tail(null)
3638+
var rtx = GetNewContext();
3639+
var inputList = null as List<int>;
3640+
var expectedList = null as List<int>;
3641+
var slicedList = rtx.Operators.Slice(inputList, 1, null);
3642+
Assert.IsNull(slicedList);
3643+
}
3644+
3645+
[TestCategory("SliceTests")]
3646+
[TestMethod]
3647+
public void Take2()
3648+
{
3649+
//The Take operator returns the first number elements from the given list.
3650+
//define "Take2": Take({ 1, 2, 3, 4 }, 2) // { 1, 2 }
3651+
var rtx = GetNewContext();
3652+
var inputList = new List<int> { 1, 2, 3, 4 };
3653+
var expectedList = new List<int> { 1, 2 };
3654+
var slicedList = rtx.Operators.Slice(inputList, 0, 2);
3655+
Assert.IsNotNull(slicedList);
3656+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3657+
}
3658+
3659+
[TestCategory("SliceTests")]
3660+
[TestMethod]
3661+
public void TakeTooMany()
3662+
{
3663+
//If the list has less than number elements, the result only contains the elements in the list.
3664+
//define "TakeTooMany": Take({ 1, 2 }, 3) // { 1, 2 }
3665+
var rtx = GetNewContext();
3666+
var inputList = new List<int> { 1, 2 };
3667+
var expectedList = new List<int> { 1, 2 };
3668+
var slicedList = rtx.Operators.Slice(inputList, 0, 3);
3669+
Assert.IsNotNull(slicedList);
3670+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3671+
}
3672+
3673+
[TestCategory("SliceTests")]
3674+
[TestMethod]
3675+
public void TakeEmpty()
3676+
{
3677+
//If number is null, or 0 or less, the result is an empty list.
3678+
//define "TakeEmpty": Take({ 1, 2, 3, 4 }, null) // { }
3679+
var rtx = GetNewContext();
3680+
var inputList = new List<int> { 1, 2, 3, 4 };
3681+
var expectedList = new List<int> { };
3682+
var slicedList = rtx.Operators.Slice(inputList, 0, 0);
3683+
Assert.IsNotNull(slicedList);
3684+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3685+
}
3686+
3687+
[TestCategory("SliceTests")]
3688+
[TestMethod]
3689+
public void TakeIsNull()
3690+
{
3691+
//If the source list is null, the result is null.
3692+
//define "TakeIsNull": Take(null, 2)
3693+
var rtx = GetNewContext();
3694+
var inputList = null as List<int>;
3695+
var expectedList = null as List<int>;
3696+
var slicedList = rtx.Operators.Slice(inputList, 0, 2);
3697+
Assert.IsNull(slicedList);
3698+
}
3699+
3700+
[TestCategory("SliceTests")]
3701+
[TestMethod]
3702+
public void Slice_array_source()
3703+
{
3704+
//Testing array as a source for Slice operator
3705+
var rtx = GetNewContext();
3706+
var inputSource = new[] { 1, 2, 3, 4 };
3707+
var expectedList = new List<int> { 1, 2 };
3708+
var slicedList = rtx.Operators.Slice(inputSource, 0, 2);
3709+
Assert.IsNotNull(slicedList);
3710+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3711+
}
3712+
3713+
[TestCategory("SliceTests")]
3714+
[TestMethod]
3715+
public void Slice_linkedList_source()
3716+
{
3717+
// Testing LinkedList as a source for Slice operator
3718+
var rtx = GetNewContext();
3719+
var inputSource = new LinkedList<int>(new[] { 1, 2, 3, 4 });
3720+
var expectedList = new List<int> { 1, 2 };
3721+
var slicedList = rtx.Operators.Slice(inputSource, 0, 2);
3722+
Assert.IsNotNull(slicedList);
3723+
CollectionAssert.AreEqual(expectedList, slicedList.ToList());
3724+
}
3725+
3726+
#endregion
35423727
}
35433728
}

Cql/Cql.Runtime/Operators/CqlOperators.ListOperators.cs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,26 +1047,23 @@ internal partial class CqlOperators
10471047
{
10481048
if (source == null)
10491049
return null;
1050-
if ((startIndex == null && endIndex == null) || !source.Any())
1051-
{
1052-
return [];
1053-
}
1054-
var si = startIndex ?? 0;
1055-
if (source is List<T> list)
1050+
1051+
if (!source.Any())
1052+
return Enumerable.Empty<T>();
1053+
1054+
if (startIndex == null && endIndex == null)
1055+
return source;
1056+
1057+
if (startIndex < 0 || endIndex <= 0)
1058+
return Enumerable.Empty<T>();
1059+
1060+
if (endIndex == null)
10561061
{
1057-
var lcm1 = list.Count - 1;
1058-
var ei = Math.Min(endIndex ?? lcm1, lcm1);
1059-
var count = ei - si + 1;
1060-
var slice = list.GetRange(si, count);
1061-
return slice;
1062+
return source.Skip(startIndex ?? 0).ToList();
10621063
}
10631064
else
10641065
{
1065-
var skip = source.Skip(si);
1066-
var result = new List<T>();
1067-
foreach (var item in skip.Take(endIndex ?? int.MaxValue))
1068-
result.Add(item);
1069-
return result;
1066+
return source.Skip(startIndex ?? 0).Take((endIndex ?? 0) - (startIndex ?? 0)).ToList();
10701067
}
10711068
}
10721069

0 commit comments

Comments
 (0)