[ https://issues.apache.org/jira/browse/GROOVY-7637?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Paul King resolved GROOVY-7637. ------------------------------- Resolution: Fixed Assignee: Paul King Fix Version/s: 2.5.0-beta-1 PR merged with some minor tweaks. Thanks! > DefaultTypeTransformation.compareTo not symmetrical > --------------------------------------------------- > > Key: GROOVY-7637 > URL: https://issues.apache.org/jira/browse/GROOVY-7637 > Project: Groovy > Issue Type: Bug > Components: groovy-jdk > Reporter: Thibault Kruse > Assignee: Paul King > Priority: Minor > Fix For: 2.5.0-beta-1 > > > DefaultTypeTransformation.compareTo(Object left, Object right) is being used > in plenty of places in Groovy. > However, for several corner cases, it does not provide symmetry, that is: > when compareTo(a, b) returns a value (does not fail), then: > signum(compareTo(a, b)) == - signum(compareTo(b, a)) > To reproduce: > {code} > static class MyNumber extends Number { > def n > MyNumber(n) { > this.n = n > } > int intValue(){n} > long longValue(){n} > float floatValue(){n} > double doubleValue(){n} > int hashCode(){-n} > boolean equals(other) { > if (other instanceof MyNumber) { return n==other.n} > return false > } > String toString() {n.toString()} > } > static class MyNumberCompareTo extends MyNumber { > MyNumberCompareTo(Object n) { > super(n) > } > int compareTo(MyNumber other) { > return n <=> other.n > } > } > static class MyNumberComparable extends MyNumberCompareTo implements > Comparable<MyNumber> { > MyNumberComparable(Object n) { > super(n) > } > int compareTo(Object other) { > return n <=> (MyNumber) other; > } > } > void testCompareTo() { > def object1 = new Object() > def object2 = new Object() > // objects > assert compareTo(null, null) == 0 > assert compareTo(object1, null) == 1 > assert compareTo(null, object1) == -1 > assert compareTo(1, 1) == 0 > shouldFail(GroovyRuntimeException) { > compareTo(object1, object2) > } > // chars, int values 49 and 50 > Character char1 = '1' as Character > Character char2 = '2' as Character > checkCompareToSymmetricSmallerThan(char1, char2) > MyNumber number1 = new MyNumber(49) > MyNumber number2 = new MyNumber(50) > MyNumberCompareTo numCompTo1 = new MyNumberCompareTo(49) > MyNumberCompareTo numCompTo2 = new MyNumberCompareTo(50) > MyNumberComparable numComp1 = new MyNumberComparable(49) > MyNumberComparable numComp2 = new MyNumberComparable(50) > List lowers = [49, 49L, 49.0, 49.0G, 49.00G, char1, '1', number1, > numCompTo1, numComp1] > List highers = [50, 50L, 50.0, 50.0G, 50.00G, char2, '2', number2, > numCompTo2, numComp2] > lowers.each { def lower -> > assert compareTo(lower, lower) == 0 > highers.each { def higher -> > checkCompareToSymmetricSmallerThan(lower, higher) > } > } > // glitch, failing with ClassCastException > shouldFail(GroovyRuntimeException) { > compareTo(1, "22") > } > shouldFail(GroovyRuntimeException) { > compareTo("22", 1) > } > // strings and chars > assert compareTo('aa1', '2' as Character) > 0 > // bug, classCast exception > assert compareTo('2' as Character, 'aa1') < 0 > assert compareTo("aa${1}", '2' as Character) > 0 > // bug, classCast exception > assert compareTo('2' as Character, "aa${1}") < 0 > // Strings and GStrings > List lowers2 = ['aa1', "aa${1}"] > List highers2 = ['bb2', "b${2}"] > lowers2.each { def lower -> > assert compareTo(lower, lower) == 0 > highers2.each { def higher -> > checkCompareToSymmetricSmallerThan(lower, higher) > } > } > } > static void checkCompareToSymmetricSmallerThan(a, b) { > try { > assert compareTo(a, b) < 0 > assert compareTo(b, a) > 0 > } catch (AssertionError e) { > System.err.print(a.class.toString() + ' compared to ' + > b.class.toString() ) > throw e > } > } > {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)