/* ----------------------------------------------------------------------------- Copyright 2021,2023-2024 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ----------------------------------------------------------------------------- */ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "comparator helper tests" { success TestChecker } unittest orderHLessThan { \ "".defaultOrder() `OrderH:lessThan` "".defaultOrder() `Matches:with` CheckValue:equals(false) \ "a".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(true) \ "b".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:lessThan` "a".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:lessThan` "b".defaultOrder() `Matches:with` CheckValue:equals(true) } unittest orderHLessThanWith { \ "".defaultOrder() `OrderH:lessThanWith>` "".defaultOrder() `Matches:with` CheckValue:equals(false) \ "a".defaultOrder() `OrderH:lessThanWith>` "abc".defaultOrder() `Matches:with` CheckValue:equals(true) \ "b".defaultOrder() `OrderH:lessThanWith>` "abc".defaultOrder() `Matches:with` CheckValue:equals(true) \ "abc".defaultOrder() `OrderH:lessThanWith>` "abc".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:lessThanWith>` "a".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:lessThanWith>` "b".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest orderHEquals { \ "".defaultOrder() `OrderH:equals` "".defaultOrder() `Matches:with` CheckValue:equals(true) \ "a".defaultOrder() `OrderH:equals` "abc".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:equals` "abc".defaultOrder() `Matches:with` CheckValue:equals(true) \ "abc".defaultOrder() `OrderH:equals` "a".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest orderHEqualsWith { \ "".defaultOrder() `OrderH:equalsWith` "".defaultOrder() `Matches:with` CheckValue:equals(true) \ "a".defaultOrder() `OrderH:equalsWith` "ABC".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:equalsWith` "ABC".defaultOrder() `Matches:with` CheckValue:equals(true) \ "abc".defaultOrder() `OrderH:equalsWith` "DEF".defaultOrder() `Matches:with` CheckValue:equals(false) \ "abc".defaultOrder() `OrderH:equalsWith` "A".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest readAtHLessThan { \ "" `ReadAtH:lessThan` "" `Matches:with` CheckValue:equals(false) \ "a" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(true) \ "b" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:lessThan` "a" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:lessThan` "b" `Matches:with` CheckValue:equals(true) } unittest readAtHLessThanWith { \ "" `ReadAtH:lessThanWith>` "" `Matches:with` CheckValue:equals(false) \ "a" `ReadAtH:lessThanWith>` "abc" `Matches:with` CheckValue:equals(true) \ "b" `ReadAtH:lessThanWith>` "abc" `Matches:with` CheckValue:equals(true) \ "abc" `ReadAtH:lessThanWith>` "abc" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:lessThanWith>` "a" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:lessThanWith>` "b" `Matches:with` CheckValue:equals(false) } unittest readAtHEquals { \ "" `ReadAtH:equals` "" `Matches:with` CheckValue:equals(true) \ "a" `ReadAtH:equals` "abc" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:equals` "abc" `Matches:with` CheckValue:equals(true) \ "abc" `ReadAtH:equals` "a" `Matches:with` CheckValue:equals(false) } unittest readAtHEqualsWith { \ "" `ReadAtH:equalsWith` "" `Matches:with` CheckValue:equals(true) \ "a" `ReadAtH:equalsWith` "ABC" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:equalsWith` "ABC" `Matches:with` CheckValue:equals(true) \ "abc" `ReadAtH:equalsWith` "DEF" `Matches:with` CheckValue:equals(false) \ "abc" `ReadAtH:equalsWith` "a" `Matches:with` CheckValue:equals(false) } concrete IgnoreCase { defines Equals } define IgnoreCase { equals (x, y) { return toLower(x) == toLower(y) } @type toLower (Char) -> (Char) toLower (c) { if (c >= 'A' && c <= 'Z') { return (c.asInt() - 'A'.asInt() + 'a'.asInt()).asChar() } else { return c } } } unittest reversed { \ 0 `Reversed.lessThan` 0 `Matches:with` CheckValue:equals(false) \ 0 `Reversed.lessThan` 1 `Matches:with` CheckValue:equals(false) \ 1 `Reversed.lessThan` 0 `Matches:with` CheckValue:equals(true) } unittest bySizeLessThan { \ "" `BySize.lessThan` "" `Matches:with` CheckValue:equals(false) \ "b" `BySize.lessThan` "ac" `Matches:with` CheckValue:equals(true) \ "ac" `BySize.lessThan` "b" `Matches:with` CheckValue:equals(false) \ "a" `BySize.lessThan` "b" `Matches:with` CheckValue:equals(false) } unittest bySizeEquals { \ "" `BySize.equals` "" `Matches:with` CheckValue:equals(true) \ "b" `BySize.equals` "ac" `Matches:with` CheckValue:equals(false) \ "ac" `BySize.equals` "b" `Matches:with` CheckValue:equals(false) \ "a" `BySize.equals` "b" `Matches:with` CheckValue:equals(true) } unittest alwaysEqualLessThan { \ "" `AlwaysEqual.lessThan` "" `Matches:with` CheckValue:equals(false) \ "b" `AlwaysEqual.lessThan` "ac" `Matches:with` CheckValue:equals(false) \ "ac" `AlwaysEqual.lessThan` "b" `Matches:with` CheckValue:equals(false) } unittest alwaysEqualEquals { \ "" `AlwaysEqual.equals` "" `Matches:with` CheckValue:equals(true) \ "b" `AlwaysEqual.equals` "ac" `Matches:with` CheckValue:equals(true) \ "ac" `AlwaysEqual.equals` "b" `Matches:with` CheckValue:equals(true) \ "a" `AlwaysEqual.equals` "b" `Matches:with` CheckValue:equals(true) } testcase "iteration tests" { success TestChecker } unittest orderHCopyTo { ValueCheck output <- ValueCheck.new(10) \ ValueOrder.wrap(false, Counter.zeroIndexed(10)) `OrderH:copyTo` output \ output.checkEnd() } unittest orderHDuplicateTo { ValueCheck output <- ValueCheck.new(10) \ ValueOrder.wrap(true, Counter.zeroIndexed(10)) `OrderH:duplicateTo` output \ output.checkEnd() } unittest readAtHCopyTo { ValueCheck output <- ValueCheck.new(10) \ ValueSource.new(false, 10) `ReadAtH:copyTo` output \ output.checkEnd() } unittest readAtHDuplicateTo { ValueCheck output <- ValueCheck.new(10) \ ValueSource.new(true, 10) `ReadAtH:duplicateTo` output \ output.checkEnd() } unittest readAtHForwardOrder { ValueSource source <- ValueSource.new(false, 10) Int expected <- 0 traverse (`ReadAtH:forwardOrder` source -> Value actual) { \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected+1 } \ expected `Matches:with` CheckValue:equals(10) } unittest readAtHForwardOrderEmpty { ValueSource source <- ValueSource.new(false, 0) traverse (`ReadAtH:forwardOrder` source -> _) { fail("not empty") } } unittest readAtHReverseOrder { ValueSource source <- ValueSource.new(false, 10) Int expected <- 9 traverse (`ReadAtH:reverseOrder` source -> Value actual) { \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected-1 } \ expected `Matches:with` CheckValue:equals(-1) } unittest readAtHReverseOrderEmpty { ValueSource source <- ValueSource.new(false, 0) traverse (`ReadAtH:reverseOrder` source -> _) { fail("not empty") } } unittest readAtHIterateWith { ValueSource source <- ValueSource.new(false, 10) Int expected <- 0 traverse (source `ReadAtH:iterateWith` `Counter.zeroIndexed` 5 -> Value actual) { \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected+1 } \ expected `Matches:with` CheckValue:equals(5) } unittest appendHFrom { [Append & Build] output <- String.builder() `AppendH:from` "123".defaultOrder() `AppendH:from` "abc".defaultOrder() \ output.build() `Matches:with` CheckValue:equals("123abc") } concrete ValueOrder { refines Order @type wrap (Bool, optional Order) -> (optional Order) } define ValueOrder { $ReadOnly[original]$ @value Bool original @value Order order wrap (original, order) { if (!present(order)) { return empty } else { return ValueOrder{ original, require(order) } } } next () { optional Order order2 <- order.next() if (present(order2)) { order <- require(order2) return self } else { return empty } } get () { return Value.new(original, order.get()) } } concrete ValueCheck { // Must append the next value in the sequence [0, size). refines Append @type new (Int) -> (ValueCheck) @value checkEnd () -> () } define ValueCheck { $ReadOnly[target]$ @value Int current @value Int target new (target) { return ValueCheck{ 0, target } } checkEnd () { \ current `Matches:with` CheckValue:equals(target) } append (x) { \ x.get() `Matches:with` CheckValue:equals(current) current <- current+1 return self } } concrete Value { // Crashes if "original" is already false. refines Duplicate // Args: // - Bool: Whether or not the value is "original". // - Int: Value to return from get(). @type new (Bool, Int) -> (Value) // Crashes if "original" is true. @value get () -> (Int) } define Value { $ReadOnly[original, value]$ @value Bool original @value Int value new (original, value) { return Value{ original, value } } get () { if (original) { fail("not duplicated") } return value } duplicate () { if (!original) { fail("already duplicated") } return Value{ false, value } } } concrete ValueSource { // readAt(i) returns Value.new(original, i). refines ReadAt // Args: // - Bool: Whether or not to mark new values as "original". // - Int: Total size. @type new (Bool, Int) -> (ValueSource) } define ValueSource { $ReadOnly[original, size]$ @value Bool original @value Int size new (original, size) { return ValueSource{ original, size } } size () { return size } readAt (i) { \ i `Matches:with` CheckValue:betweenEquals(0, size-1) return Value.new(original, i) } } testcase "formatting tests" { success TestChecker } unittest emptyValue { \ FormattedH:try(empty).formatted() `Matches:with` CheckValue:equals("Char{empty}") \ FormattedH:try(empty).formatted() `Matches:with` CheckValue:equals("all{empty}") } unittest formattedValue { \ FormattedH:try(123).formatted() `Matches:with` CheckValue:equals("123") } unittest nonFormattedValue { \ FormattedH:try(String.builder()).formatted() `Matches:with` CheckValue:equals("[Append&Build]{?}") }