[ruby-core:127084] [Ruby Bug#22432] Range#include? returns true for the end of an empty range of single-character Strings
Issue #22432 has been reported by sferik (Erik Berlin). ---------------------------------------- Bug #22432: Range#include? returns true for the end of an empty range of single-character Strings https://bugs.ruby-lang.org/issues/22432 * Author: sferik (Erik Berlin) * Status: Open * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- A Range whose ends are both single ASCII characters reports that it includes its end even when the range is empty. ```ruby r = "z".."a" r.to_a #=> [] r.include?("a") #=> true r.member?("a") #=> true r.cover?("a") #=> false r === "a" #=> false ``` I expect `include?` and `member?` to return false here, as `cover?` does and as iterating the range implies. The same happens with digits, for example `("1".."0").include?("0")`. Only the end is affected. Other values are correctly reported as not included: ```ruby ("z".."a").include?("z") #=> false ("z".."a").include?("m") #=> false ``` `Range#include?` has a shortcut for ranges of single-character Strings, which compares the characters instead of iterating. It is in `rb_str_include_range_p` in string.c: ```c if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { if (b <= v && v < e) return Qtrue; return RBOOL(!RTEST(exclusive) && v == e); } ``` The last line returns true whenever the value equals the end, without checking that the begin is not after the end. -- https://bugs.ruby-lang.org/
Issue #22432 has been updated by eightbitraptor (Matt V-H). Thanks for the report. Addressed in https://github.com/ruby/ruby/pull/19317 ---------------------------------------- Bug #22432: Range#include? returns true for the end of an empty range of single-character Strings https://bugs.ruby-lang.org/issues/22432#change-119483 * Author: sferik (Erik Berlin) * Status: Open * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- A Range whose ends are both single ASCII characters reports that it includes its end even when the range is empty. ```ruby r = "z".."a" r.to_a #=> [] r.include?("a") #=> true r.member?("a") #=> true r.cover?("a") #=> false r === "a" #=> false ``` I expect `include?` and `member?` to return false here, as `cover?` does and as iterating the range implies. The same happens with digits, for example `("1".."0").include?("0")`. Only the end is affected. Other values are correctly reported as not included: ```ruby ("z".."a").include?("z") #=> false ("z".."a").include?("m") #=> false ``` `Range#include?` has a shortcut for ranges of single-character Strings, which compares the characters instead of iterating. It is in `rb_str_include_range_p` in string.c: ```c if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { if (b <= v && v < e) return Qtrue; return RBOOL(!RTEST(exclusive) && v == e); } ``` The last line returns true whenever the value equals the end, without checking that the begin is not after the end. -- https://bugs.ruby-lang.org/
Issue #22432 has been updated by sferik (Erik Berlin). @eightbitraptor: Thanks. I previously submitted a nearly identical test for this in https://github.com/ruby/ruby/pull/19313. CI is already green there. ---------------------------------------- Bug #22432: Range#include? returns true for the end of an empty range of single-character Strings https://bugs.ruby-lang.org/issues/22432#change-119484 * Author: sferik (Erik Berlin) * Status: Open * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- A Range whose ends are both single ASCII characters reports that it includes its end even when the range is empty. ```ruby r = "z".."a" r.to_a #=> [] r.include?("a") #=> true r.member?("a") #=> true r.cover?("a") #=> false r === "a" #=> false ``` I expect `include?` and `member?` to return false here, as `cover?` does and as iterating the range implies. The same happens with digits, for example `("1".."0").include?("0")`. Only the end is affected. Other values are correctly reported as not included: ```ruby ("z".."a").include?("z") #=> false ("z".."a").include?("m") #=> false ``` `Range#include?` has a shortcut for ranges of single-character Strings, which compares the characters instead of iterating. It is in `rb_str_include_range_p` in string.c: ```c if (ISASCII(b) && ISASCII(e) && ISASCII(v)) { if (b <= v && v < e) return Qtrue; return RBOOL(!RTEST(exclusive) && v == e); } ``` The last line returns true whenever the value equals the end, without checking that the begin is not after the end. -- https://bugs.ruby-lang.org/
participants (2)
-
eightbitraptor (Matt V-H) -
sferik (Erik Berlin)