test: cover reverseFlipsTheCharactersOfAString
This commit is contained in:
1 parent
5eedad6404
commit
795ba03620
1 file changed
+173
@@ -289,4 +289,177 @@ class EvaluatorTest {
|
||||
assertFailsWith<KestrelException> { evalConstant(CallExpression("MOD", listOf(intLit(1), intLit(0)))) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reverseFlipsTheCharactersOfAString() {
|
||||
assertEquals(Value.TextValue("cba"), evalConstant(CallExpression("REVERSE", listOf(textLit("abc")))))
|
||||
assertEquals(Value.TextValue(""), evalConstant(CallExpression("REVERSE", listOf(textLit("")))))
|
||||
assertFailsWith<KestrelException> { evalConstant(CallExpression("REVERSE", listOf(intLit(1)))) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun leftAndRightTakeCharactersFromEachEndAndClampToTheStringsLength() {
|
||||
assertEquals(Value.TextValue("hel"), evalConstant(CallExpression("LEFT", listOf(textLit("hello"), intLit(3)))))
|
||||
assertEquals(Value.TextValue("llo"), evalConstant(CallExpression("RIGHT", listOf(textLit("hello"), intLit(3)))))
|
||||
assertEquals(Value.TextValue("hello"), evalConstant(CallExpression("LEFT", listOf(textLit("hello"), intLit(100)))))
|
||||
assertEquals(Value.TextValue("hello"), evalConstant(CallExpression("RIGHT", listOf(textLit("hello"), intLit(100)))))
|
||||
assertEquals(Value.TextValue(""), evalConstant(CallExpression("LEFT", listOf(textLit("hello"), intLit(0)))))
|
||||
assertEquals(Value.TextValue(""), evalConstant(CallExpression("RIGHT", listOf(textLit("hello"), intLit(-1)))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signReturnsMinusOneZeroOrOneAcrossEveryNumericType() {
|
||||
assertEquals(Value.IntegerValue(1), evalConstant(CallExpression("SIGN", listOf(intLit(5)))))
|
||||
assertEquals(Value.IntegerValue(-1), evalConstant(CallExpression("SIGN", listOf(intLit(-5)))))
|
||||
assertEquals(Value.IntegerValue(0), evalConstant(CallExpression("SIGN", listOf(intLit(0)))))
|
||||
assertEquals(Value.IntegerValue(1), evalConstant(CallExpression("SIGN", listOf(realLit(0.1)))))
|
||||
assertEquals(Value.IntegerValue(-1), evalConstant(CallExpression("SIGN", listOf(realLit(-0.1)))))
|
||||
val negativeDecimal = LiteralExpression(Value.DecimalValue(BigDecimal("-3.50")))
|
||||
assertEquals(Value.IntegerValue(-1), evalConstant(CallExpression("SIGN", listOf(negativeDecimal))))
|
||||
assertFailsWith<KestrelException> { evalConstant(CallExpression("SIGN", listOf(textLit("x")))) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun truncCutsDigitsTowardZeroWithoutRoundingUnlikeRound() {
|
||||
assertEquals(Value.IntegerValue(4), evalConstant(CallExpression("TRUNC", listOf(intLit(4)))))
|
||||
assertEquals(Value.RealValue(1.9), evalConstant(CallExpression("TRUNC", listOf(realLit(1.99), intLit(1)))))
|
||||
assertEquals(Value.RealValue(-1.9), evalConstant(CallExpression("TRUNC", listOf(realLit(-1.99), intLit(1)))))
|
||||
val decimal = LiteralExpression(Value.DecimalValue(BigDecimal("1.999")))
|
||||
assertEquals(
|
||||
Value.DecimalValue(BigDecimal("1.99")),
|
||||
evalConstant(CallExpression("TRUNC", listOf(decimal, intLit(2))))
|
||||
)
|
||||
// TRUNC never rounds up, exactly the case where it must differ from ROUND's HALF_UP default.
|
||||
assertEquals(Value.RealValue(1.0), evalConstant(CallExpression("TRUNC", listOf(realLit(1.9)))))
|
||||
assertEquals(Value.RealValue(2.0), evalConstant(CallExpression("ROUND", listOf(realLit(1.9)))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun greatestAndLeastPickTheOrderingExtremeAcrossMixedNumericTypes() {
|
||||
assertEquals(
|
||||
Value.IntegerValue(7),
|
||||
evalConstant(CallExpression("GREATEST", listOf(intLit(3), intLit(7), intLit(1))))
|
||||
)
|
||||
assertEquals(
|
||||
Value.IntegerValue(1),
|
||||
evalConstant(CallExpression("LEAST", listOf(intLit(3), intLit(7), intLit(1))))
|
||||
)
|
||||
assertEquals(
|
||||
Value.RealValue(7.5),
|
||||
evalConstant(CallExpression("GREATEST", listOf(intLit(3), realLit(7.5), intLit(1))))
|
||||
)
|
||||
assertEquals(Value.TextValue("banana"), evalConstant(CallExpression("GREATEST", listOf(textLit("apple"), textLit("banana")))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun greatestAndLeastPropagateNullAndRequireAtLeastTwoArguments() {
|
||||
assertEquals(Value.NullValue, evalConstant(CallExpression("GREATEST", listOf(intLit(1), nullLit))))
|
||||
assertEquals(Value.NullValue, evalConstant(CallExpression("LEAST", listOf(nullLit, intLit(1)))))
|
||||
assertFailsWith<KestrelException> { evalConstant(CallExpression("GREATEST", listOf(intLit(1)))) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun functionRequiringTextRejectsWrongType() {
|
||||
assertFailsWith<KestrelException> { evalConstant(CallExpression("UPPER", listOf(intLit(1)))) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNullDetectsNullness() {
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(IsNullExpression(nullLit, negated = false)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(IsNullExpression(intLit(1), negated = false)))
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(IsNullExpression(intLit(1), negated = true)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(IsNullExpression(nullLit, negated = true)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun inMatchesAnyListMember() {
|
||||
assertEquals(
|
||||
Value.BooleanValue(true),
|
||||
evalConstant(InExpression(intLit(2), listOf(intLit(1), intLit(2), intLit(3)), negated = false))
|
||||
)
|
||||
assertEquals(
|
||||
Value.BooleanValue(false),
|
||||
evalConstant(InExpression(intLit(9), listOf(intLit(1), intLit(2)), negated = false))
|
||||
)
|
||||
assertEquals(
|
||||
Value.BooleanValue(false),
|
||||
evalConstant(InExpression(intLit(2), listOf(intLit(1), intLit(2)), negated = true))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun inWithNullOperandIsNull() {
|
||||
assertEquals(Value.NullValue, evalConstant(InExpression(nullLit, listOf(intLit(1)), negated = false)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun inWithUnmatchedNullInListIsNullNotFalse() {
|
||||
assertEquals(
|
||||
Value.NullValue,
|
||||
evalConstant(InExpression(intLit(9), listOf(intLit(1), nullLit), negated = false))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun betweenIsInclusiveOnBothEnds() {
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(BetweenExpression(intLit(18), intLit(18), intLit(65), negated = false)))
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(BetweenExpression(intLit(65), intLit(18), intLit(65), negated = false)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(BetweenExpression(intLit(17), intLit(18), intLit(65), negated = false)))
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(BetweenExpression(intLit(17), intLit(18), intLit(65), negated = true)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun likeSupportsPercentAndUnderscoreWildcards() {
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(LikeExpression(textLit("hello"), textLit("h%"), negated = false)))
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(LikeExpression(textLit("hello"), textLit("h_llo"), negated = false)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(LikeExpression(textLit("hello"), textLit("world"), negated = false)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(LikeExpression(textLit("hello"), textLit("h%"), negated = true)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun likeEscapesRegexMetacharactersInPattern() {
|
||||
assertEquals(Value.BooleanValue(true), evalConstant(LikeExpression(textLit("a.b"), textLit("a.b"), negated = false)))
|
||||
assertEquals(Value.BooleanValue(false), evalConstant(LikeExpression(textLit("axb"), textLit("a.b"), negated = false)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchedCaseReturnsFirstMatchingBranch() {
|
||||
val expression = CaseExpression(
|
||||
operand = null,
|
||||
branches = listOf(
|
||||
CaseBranch(bin(BinaryOperator.Less, intLit(10), intLit(5)), textLit("small")),
|
||||
CaseBranch(bin(BinaryOperator.GreaterEqual, intLit(10), intLit(5)), textLit("big"))
|
||||
),
|
||||
elseExpression = textLit("none")
|
||||
)
|
||||
assertEquals(Value.TextValue("big"), evalConstant(expression))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun simpleCaseComparesOperandAgainstBranches() {
|
||||
val expression = CaseExpression(
|
||||
operand = intLit(2),
|
||||
branches = listOf(CaseBranch(intLit(1), textLit("one")), CaseBranch(intLit(2), textLit("two"))),
|
||||
elseExpression = textLit("other")
|
||||
)
|
||||
assertEquals(Value.TextValue("two"), evalConstant(expression))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun caseFallsThroughToElseWhenNoBranchMatches() {
|
||||
val expression = CaseExpression(
|
||||
operand = null,
|
||||
branches = listOf(CaseBranch(falseLit, textLit("nope"))),
|
||||
elseExpression = textLit("fallback")
|
||||
)
|
||||
assertEquals(Value.TextValue("fallback"), evalConstant(expression))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun caseWithoutElseYieldsNullWhenNoBranchMatches() {
|
||||
val expression = CaseExpression(operand = null, branches = listOf(CaseBranch(falseLit, textLit("nope"))), elseExpression = null)
|
||||
assertEquals(Value.NullValue, evalConstant(expression))
|
||||
}
|
||||
|
||||
private fun cast(operand: Expression, type: ColumnType, precision: Int? = null, scale: Int? = null): Expression =
|
||||
CastExpression(operand, type, precision, scale)
|
||||
}
|
||||
Reference in new issue
Block a user