-
Notifications
You must be signed in to change notification settings - Fork 21
Specification Test Nonconformity & Notes
Here we document any nonconformity in the specification tests.
Expression:
minimum Decimal
Expected result:
-99999999999999999999.99999999
Actual output:
-79228162514264337593543950335
Rationale:
Per the spec:
Note that if implementations support larger and/or more precise values than the minimum required precision and scale for Decimal, DateTime, and Time values, they will return the minimum representable decimal for the implementation.
Since the SDK uses the C# decimal type to represent the ELM System.Decimal type, we can represent smaller decimals than the minimum required by the specification.
Action:
Test skipped
Recommendation:
Change the expression in the test to be minimum Decimal <= -99999999999999999999.99999999
with an expected output of true
Expression:
maximum Decimal
Expected result:
99999999999999999999.99999999
Actual output:
79228162514264337593543950335
Rationale:
Per the spec:
Note that if implementations support larger and/or more precise values than the minimum required precision and scale for Decimal, DateTime, and Time values, they will return the minimum representable decimal for the implementation.
Since the SDK uses the C# decimal type to represent the ELM System.Decimal type, we can represent larger decimals than the maximum required by the specification.
Action:
Test skipped
Recommendation:
Change the expression in the test to be maximum Decimal >= 99999999999999999999.99999999
with an expected output of true
Expression:
1.0 'cm' * 2.0 'cm'
Expected result:
2.0'cm2'
Actual output:
Rationale:
Unit arithmetic is not yet supported. Quantities used in arithmetic expressions must have the default UCUM unit of 1
.
Action:
Test skipped
Expression:
Power(2, -2)
Expected result:
0.25
Actual output:
0
Rationale:
As converted to ELM, the result type of this expression is defined to be System.Integer
. Obeying this result type requires that we truncate from 0.25
, the mathematically correct result, to 0
.
Action:
Test skipped
Recommendation:
The spec discusses behavior for mixed argument types, but does not explicitly state that when Power
is used with two Integer
arguments that the result type should also be an Integer
and decimal portions will be truncated. Given the behavior of the cql-to-elm reference implementation, that behavior is established. This contradicts the expected result of the test. Either the translator has to be updated to match the test, or the test should have an expected outcome of 0
. In both cases, the spec should be updated to clarify this.
Expression:
Round(-0.5)
Expected result:
1.0
Actual output:
0
Rationale:
The spec uses the language "traditional round" to describe the rounding method. We use the default rounding strategy which is described in the language as "to nearest." For reference, .NET has devoted significant thought to this here.
This test contradicts the others when using the "to nearest" rounding.
Recommendation:
Clarify the rounding strategy, or fix the expected output of this test.
See Round0D5
See Multiply1CMBy2CM
Expression:
1'cm' ~ 0.01'm'
Expected result:
true
Actual output:
false
Rationale:
Quantity comparison of non-same units is not yet supported. Quantities used in comparison expressions must have the same unit.
Action:
Test skipped
See EquivEqCM1M01
Affected tests
- DateTimeDurationBetweenYear
- DateTimeDurationBetweenUncertainInterval
- DateTimeDurationBetweenUncertainInterval2
- DateTimeDurationBetweenUncertainAdd
- DateTimeDurationBetweenUncertainSubtract
- DateTimeDurationBetweenUncertainMultiply
- DateTimeDurationBetweenUncertainDiv
- DateTimeDurationBetweenMonthUncertain2
Example expression (DateTimeDurationBetweenYear):
years between DateTime(2005) and DateTime(2010)
Expected result:
Interval[4,5]
Actual output:
5
Rationale:
Per the spec:
The result of this operation is always an integer; any fractional periods are dropped.
Action:
Tests skipped
Recommendation:
Change the expected output of these tests to be a System.Integer
, as indicated by the spec; alternatively, update the specification to be clear that the Duration
operator returns an interval (to account for uncertainty), where certain results will be expressed as point intervals. The latter would be a breaking change and should be done with caution.
Example tests
- DateTimeAdd2YearsByDays
Recommendation:
Per the spec:
For partial date/time values where the time-valued quantity is more precise than the partial date/time, the operation is performed by converting the time-based quantity to the most precise value specified in first argument (truncating any resulting decimal portion) and then adding it to the first argument.
The method for converting 730 days
to years would be to divide 730 by 365 days (or to multiply by 1/365). Floating point math computations can produce a value that is not exactly 2.0 but is rather something like 1.99999999986. In this case, if the implementation truncates the decimal portion after the imprecise floating point mathematics, it could result in 1 year instead of 2, as expected by the test (DateTime(2014) + 730 days = @2016
).
This SDK rounds all conversions to a precision of 8 decimal places, which will round the imprecise sub-2.0 floating point value to 2.0, thus satisfying this test.
Our recommendation is to update the spec to formalize this rounding process.
Expression:
Interval(null, 5] meets after Interval[11, null)
Expected result:
false
Actual output:
null
Rationale:
This test has the same basic pattern as another test, TestIntersectNull
, whose expression is Interval[1, 10] intersect Interval[5, null)
and whose expected result is null
because having an open null
endpoint makes this operation undefined. The meets after
operator is specifically concerned with the low value of the first operand and the high value of the second operand, as per the spec:
the meets after operator returns true if the first interval starts immediately after the second interval ends.
Action:
Test skipped
Recommendation:
Interval tests where any of the operands contain a low or high value which is both null
and open should behave the same way.
Expression:
Interval[@T12:00:00.000, @T21:59:59.999] properly includes @T12:00:00.000
Expected result:
false
Actual output:
false
Recommendation:
The specification is unclear about this. It says:
For the point overload, this operator returns true if the interval contains (i.e. includes) the point, and the interval is not a unit interval containing only the point.
The language in the spec should be clarified and reworded, e.g.:
For the point overload, this operator returns true if the interval contains (i.e. includes) the point and the point is not exactly equal to either the start or the end of the interval. For point intervals whose value is the point, this operator returns
false
.