From 2af92d0ebcbeca6d3d85a27c8193273080a63090 Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Mon, 4 Jun 2018 10:52:51 +0900 Subject: Let inspect recursion do the right thing --- test/t/array.rb | 3 ++- test/t/hash.rb | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test/t/array.rb b/test/t/array.rb index ecec39363..3ed3d54ec 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -318,11 +318,12 @@ end assert('Array#to_s', '15.2.12.5.31 / 15.2.12.5.32') do a = [2, 3, 4, 5] + a[4] = a r1 = a.to_s r2 = a.inspect assert_equal(r2, r1) - assert_equal("[2, 3, 4, 5]", r1) + assert_equal("[2, 3, 4, 5, [...]]", r1) end assert('Array#==', '15.2.12.5.33') do diff --git a/test/t/hash.rb b/test/t/hash.rb index 5403a5901..63029be42 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -351,11 +351,13 @@ end assert('Hash#inspect') do h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 } + h["recur"] = h ret = h.to_s assert_include ret, '"c"=>300' assert_include ret, '"a"=>100' assert_include ret, '"d"=>400' + assert_include ret, '"recur"=>{...}' end assert('Hash#rehash') do -- cgit v1.2.3 From 623e15936a6c8b8ecaf9dca341be80c9316fd8be Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Apr 2019 19:03:46 +0900 Subject: `Module#alias_method` should return `self` in ISO standard --- src/class.c | 2 +- test/t/module.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/src/class.c b/src/class.c index 5c5ee9d17..eaef787f7 100644 --- a/src/class.c +++ b/src/class.c @@ -1843,7 +1843,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; } void diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..da0f78fad 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -25,6 +25,17 @@ assert('Module', '15.2.2') do assert_equal Class, Module.class end +assert('Module#alias_method', '15.2.2.4.8') do + cls = Class.new do + def foo + "FOO" + end + end + + assert_same(cls, cls.alias_method(:bar, :foo)) + assert_equal("FOO", cls.new.bar) +end + # TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do assert('Module#ancestors', '15.2.2.4.9') do -- cgit v1.2.3 From f65b35dc9f5428e7d07b304c01c7836d5be7ec52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Apr 2019 21:31:12 +0900 Subject: Fix test for `Array#slice` --- test/t/array.rb | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/t/array.rb b/test/t/array.rb index 2b19fe0d4..3df99056f 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -298,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do end assert('Array#slice', '15.2.12.5.29') do - a = "12345".slice(1, 3) - b = a.slice(0) - - assert_equal("2:", "#{b}:") - assert_equal(2, [1,2,3].[](1)) + a = [*(1..100)] + b = a.dup + + assert_equal(1, a.slice(0)) + assert_equal(100, a.slice(99)) + assert_nil(a.slice(100)) + assert_equal(100, a.slice(-1)) + assert_equal(99, a.slice(-2)) + assert_equal(1, a.slice(-100)) + assert_nil(a.slice(-101)) + assert_equal([1], a.slice(0,1)) + assert_equal([100], a.slice(99,1)) + assert_equal([], a.slice(100,1)) + assert_equal([100], a.slice(99,100)) + assert_equal([100], a.slice(-1,1)) + assert_equal([99], a.slice(-2,1)) + assert_equal([10, 11, 12], a.slice(9, 3)) + assert_equal([10, 11, 12], a.slice(-91, 3)) + assert_nil(a.slice(-101, 2)) + assert_equal([1], a.slice(0..0)) + assert_equal([100], a.slice(99..99)) + assert_equal([], a.slice(100..100)) + assert_equal([100], a.slice(99..200)) + assert_equal([100], a.slice(-1..-1)) + assert_equal([99], a.slice(-2..-2)) + assert_equal([10, 11, 12], a.slice(9..11)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_equal([10, 11, 12], a.slice(-91..-89)) + assert_nil(a.slice(-101..-1)) + assert_nil(a.slice(10, -3)) + assert_equal([], a.slice(10..7)) + assert_equal(b, a) end assert('Array#unshift', '15.2.12.5.30') do -- cgit v1.2.3 From 7b0ebed033777cd8bdb8e3668e5c49cfe1b69c5d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Apr 2019 19:17:00 +0900 Subject: Use `mrb_immediate_p()` in `mrb_obj_freeze()` and `mrb_obj_frozen()` --- src/etc.c | 2 ++ src/kernel.c | 44 ++++++-------------------------------------- test/t/kernel.rb | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 38 deletions(-) (limited to 'test') diff --git a/src/etc.c b/src/etc.c index 12d948a55..6c5fb7480 100644 --- a/src/etc.c +++ b/src/etc.c @@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ diff --git a/src/kernel.c b/src/kernel.c index 7890e3dac..d9a1d36ce 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -434,24 +434,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } } return self; } @@ -459,26 +446,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_frozen(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d99358c0c..bf7dbe94c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -247,6 +247,23 @@ assert('Kernel#freeze') do assert_equal obj, obj.freeze assert_equal 0, 0.freeze assert_equal :a, :a.freeze + assert_equal true, true.freeze + assert_equal false, false.freeze + assert_equal nil, nil.freeze + skip unless Object.const_defined?(:Float) + assert_equal 0.0, 0.0.freeze +end + +assert('Kernel#frozen?') do + assert_false "".frozen? + assert_true "".freeze.frozen? + assert_true 0.frozen? + assert_true :a.frozen? + assert_true true.frozen? + assert_true false.frozen? + assert_true nil.frozen? + skip unless Object.const_defined?(:Float) + assert_true 0.0.frozen? end assert('Kernel#global_variables', '15.3.1.3.14') do -- cgit v1.2.3 From 6626fbc5006d662f8fc69a51660ae7c1e998a1f0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 12 Apr 2019 22:27:07 +0900 Subject: Refine `assert_float` Avoid arithmetic operations when `exp` and/or `act` are infinity or NaN. --- test/assert.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..e0fac4d90 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,11 +149,11 @@ end # Fails unless +exp+ is equal to +act+ in terms of a Float def assert_float(exp, act, msg = nil) e, a = exp.to_f, act.to_f - if (e.infinite? || a.infinite?) && e != a || + if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE + flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") + elsif (e.infinite? || a.infinite?) && e != a || e.nan? && !a.nan? || !e.nan? && a.nan? flunk(msg, " Expected #{act} to be #{exp}.") - elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE - flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.") else pass end -- cgit v1.2.3 From 716a99b069461b11c2b46099119f8578cd2c8f3f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 21:38:47 +0900 Subject: Add `assert_match` and `assert_not_match` --- mrbgems/mruby-test/driver.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ test/assert.rb | 33 ++++++++++ test/t/module.rb | 7 +-- 3 files changed, 181 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index fd180b1bb..9e3dbea9d 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -62,6 +62,151 @@ t_print(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +#define UNESCAPE(p, endp) ((p) != (endp) && *(p) == '\\' ? (p)+1 : (p)) +#define CHAR_CMP(c1, c2) ((unsigned char)(c1) - (unsigned char)(c2)) + +static const char * +str_match_bracket(const char *p, const char *pat_end, + const char *s, const char *str_end) +{ + mrb_bool ok = FALSE, negated = FALSE; + + if (p == pat_end) return NULL; + if (*p == '!' || *p == '^') { + negated = TRUE; + ++p; + } + + while (*p != ']') { + const char *t1 = p; + if ((t1 = UNESCAPE(t1, pat_end)) == pat_end) return NULL; + if ((p = t1 + 1) == pat_end) return NULL; + if (p[0] == '-' && p[1] != ']') { + const char *t2 = p + 1; + if ((t2 = UNESCAPE(t2, pat_end)) == pat_end) return NULL; + p = t2 + 1; + if (!ok && CHAR_CMP(*t1, *s) <= 0 && CHAR_CMP(*s, *t2) <= 0) ok = TRUE; + } + else { + if (!ok && CHAR_CMP(*t1, *s) == 0) ok = TRUE; + } + } + + return ok == negated ? NULL : p + 1; +} + +static mrb_bool +str_match_no_brace_p(const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *s = str; + const char *pat_end = pat + pat_len, *str_end = str + str_len; + const char *p_tmp = NULL, *s_tmp = NULL; + + for (;;) { + if (p == pat_end) return s == str_end; + switch (*p) { + case '*': + do { ++p; } while (p != pat_end && *p == '*'); + if (UNESCAPE(p, pat_end) == pat_end) return TRUE; + if (s == str_end) return FALSE; + p_tmp = p; + s_tmp = s; + continue; + case '?': + if (s == str_end) return FALSE; + ++p; + ++s; + continue; + case '[': { + const char *t; + if (s == str_end) return FALSE; + if ((t = str_match_bracket(p+1, pat_end, s, str_end))) { + p = t; + ++s; + continue; + } + goto L_failed; + } + } + + /* ordinary */ + p = UNESCAPE(p, pat_end); + if (s == str_end) return p == pat_end; + if (p == pat_end) goto L_failed; + if (*p++ != *s++) goto L_failed; + continue; + + L_failed: + if (p_tmp && s_tmp) { + /* try next '*' position */ + p = p_tmp; + s = ++s_tmp; + continue; + } + + return FALSE; + } +} + +#define COPY_AND_INC(dst, src, len) \ + do { memcpy(dst, src, len); dst += len; } while (0) + +static mrb_bool +str_match_p(mrb_state *mrb, + const char *pat, mrb_int pat_len, + const char *str, mrb_int str_len) +{ + const char *p = pat, *pat_end = pat + pat_len; + const char *lbrace = NULL, *rbrace = NULL; + int nest = 0; + mrb_bool ret = FALSE; + + for (; p != pat_end; ++p) { + if (*p == '{' && nest++ == 0) lbrace = p; + else if (*p == '}' && lbrace && --nest == 0) { rbrace = p; break; } + else if (*p == '\\' && ++p == pat_end) break; + } + + if (lbrace && rbrace) { + /* expand brace */ + char *ex_pat = (char *)mrb_malloc(mrb, pat_len-2); /* expanded pattern */ + char *ex_p = ex_pat; + + COPY_AND_INC(ex_p, pat, lbrace-pat); + p = lbrace; + while (p < rbrace) { + char *orig_ex_p = ex_p; + const char *t = ++p; + for (nest = 0; p < rbrace && !(*p == ',' && nest == 0); ++p) { + if (*p == '{') ++nest; + else if (*p == '}') --nest; + else if (*p == '\\' && ++p == rbrace) break; + } + COPY_AND_INC(ex_p, t, p-t); + COPY_AND_INC(ex_p, rbrace+1, pat_end-rbrace-1); + if ((ret = str_match_p(mrb, ex_pat, ex_p-ex_pat, str, str_len))) break; + ex_p = orig_ex_p; + } + mrb_free(mrb, ex_pat); + } + else if (!lbrace && !rbrace) { + ret = str_match_no_brace_p(pat, pat_len, str, str_len); + } + + return ret; +} + +static mrb_value +m_str_match_p(mrb_state *mrb, mrb_value self) +{ + const char *pat, *str; + mrb_int pat_len, str_len; + + mrb_get_args(mrb, "ss", &pat, &pat_len, &str, &str_len); + return mrb_bool_value(str_match_p(mrb, pat, pat_len, str, str_len)); +} + void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) { @@ -69,6 +214,7 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) krn = mrb->kernel_module; mrb_define_method(mrb, krn, "t_print", t_print, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "_str_match?", m_str_match_p, MRB_ARGS_REQ(2)); mrbtest = mrb_define_module(mrb, "Mrbtest"); diff --git a/test/assert.rb b/test/assert.rb index c57b04c12..4b01bd450 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -136,6 +136,39 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +## +# Fail unless +str+ matches against +pattern+. +# +# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the +# following metacharacters: +# +# * :: +# Matches any string. +# +# ? :: +# Matches any one character. +# +# [_SET_], [^_SET_] ([!_SET_]) :: +# Matches any one character in _SET_. Behaves like character sets in +# Regexp, including set negation ([^a-z]). +# +# {_A_,_B_} :: +# Matches pattern _A_ or pattern _B_. +# +# \ :: +# Escapes the next character. +def assert_match(*args); _assert_match(true, *args) end +def assert_not_match(*args); _assert_match(false, *args) end +def _assert_match(affirmed, pattern, str, msg = nil) + receiver, *args = RUBY_ENGINE == "mruby" ? + [self, :_str_match?, pattern, str] : + [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] + unless ret = !receiver.__send__(*args) == !affirmed + diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..1694ef577 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -640,11 +640,8 @@ assert('Module#to_s') do assert_equal 'SetOuter', SetOuter.to_s assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s - mod = Module.new - cls = Class.new - - assert_equal "#", Module.new.to_s + assert_match "#", Class.new.to_s end assert('Module#inspect') do -- cgit v1.2.3 From 4a8b88f7757f71d7d88b89764b533dd5ba59fd44 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 19 Apr 2019 20:14:23 +0900 Subject: Add type check (conversion) in `String#[]=` Before this patch: 'a'[0] = 1 #=> 1 'a'[:a] = '1' #=> ArgumentError 'a'[:a, 0] = '1' #=> ArgumentError 'a'[0, :a] = '1' #=> ArgumentError 'a'[0, 1] = 1 #=> 1 After this patch / Ruby: 'a'[0] = 1 #=> TypeError 'a'[:a] = '1' #=> TypeError 'a'[:a, 0] = '1' #=> TypeError 'a'[0, :a] = '1' #=> TypeError 'a'[0, 1] = 1 #=> TypeError --- mrblib/string.rb | 11 ++++++----- test/t/string.rb | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/mrblib/string.rb b/mrblib/string.rb index 9ad8e8e73..e9eb2be1d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -197,12 +197,12 @@ class String def []=(*args) anum = args.size if anum == 2 - pos, value = args + pos, value = args[0], args[1].__to_str case pos when String posnum = self.index(pos) if posnum - b = self[0, posnum.to_i] + b = self[0, posnum] a = self[(posnum + pos.length)..-1] self.replace([b, value, a].join('')) else @@ -217,17 +217,18 @@ class String end return self[head, tail-head]=value else + pos = pos.__to_int pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + 1..-1] self.replace([b, value, a].join('')) end return value elsif anum == 3 - pos, len, value = args + pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str pos += self.length if pos < 0 if pos < 0 || pos > self.length raise IndexError, "index #{args[0]} out of string" @@ -235,7 +236,7 @@ class String if len < 0 raise IndexError, "negative length #{len}" end - b = self[0, pos.to_i] + b = self[0, pos] a = self[pos + len..-1] self.replace([b, value, a].join('')) return value diff --git a/test/t/string.rb b/test/t/string.rb index cf3702cbe..404cf03e1 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -161,6 +161,9 @@ assert('String#[]=') do assert_equal 'aXc', e end + assert_raise(TypeError) { 'a'[0] = 1 } + assert_raise(TypeError) { 'a'[:a] = '1' } + # length of args is 2 a1 = 'abc' assert_raise(IndexError) do @@ -197,6 +200,10 @@ assert('String#[]=') do assert_raise(IndexError) do b3['XX'] = 'Y' end + + assert_raise(TypeError) { 'a'[:a, 0] = '1' } + assert_raise(TypeError) { 'a'[0, :a] = '1' } + assert_raise(TypeError) { 'a'[0, 1] = 1 } end assert('String#capitalize', '15.2.10.5.7') do -- cgit v1.2.3 From cdb458ed4e07698ecb028bfe397fa273ed454e13 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 21 Apr 2019 20:34:39 +0900 Subject: Commented out `String#scan` because it is not implemented yet --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 7 ++++--- mrblib/string.rb | 21 +++++++++------------ test/t/string.rb | 4 +++- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 457687268..89472ef01 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -244,9 +244,10 @@ class Enumerator # # === Examples # - # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"] + # Array.new(3) #=> [nil, nil, nil] + # Array.new(3) { |i| i } #=> [0, 1, 2] + # Array.to_enum(:new, 3).to_a #=> [0, 1, 2] + # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2] # # obj = Object.new # diff --git a/mrblib/string.rb b/mrblib/string.rb index e9eb2be1d..c92a9e7be 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -105,18 +105,15 @@ class String self.replace(str) end - ## - # Calls the given block for each match of +pattern+ - # If no block is given return an array with all - # matches of +pattern+. - # - # ISO 15.2.10.5.32 - def scan(reg, &block) - ### *** TODO *** ### - unless Object.const_defined?(:Regexp) - raise NotImplementedError, "scan not available (yet)" - end - end +# ## +# # Calls the given block for each match of +pattern+ +# # If no block is given return an array with all +# # matches of +pattern+. +# # +# # ISO 15.2.10.5.32 +# def scan(pattern, &block) +# # TODO: String#scan is not implemented yet +# end ## # Replace only the first match of +pattern+ with diff --git a/test/t/string.rb b/test/t/string.rb index 404cf03e1..e563db55a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -509,7 +509,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_equal nil, str.index("さ") end if UTF8STRING -# 'String#scan', '15.2.10.5.32' will be tested in mrbgems. +# assert('String#scan', '15.2.10.5.32') do +# # Not implemented yet +# end assert('String#size', '15.2.10.5.33') do assert_equal 3, 'abc'.size -- cgit v1.2.3 From 0debf154ee9aa4c4f9aa0190a54a810801c3d31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 17:35:49 +0900 Subject: Add `assert_predicate` and `assert_operator` --- test/assert.rb | 20 ++++++++++++++++++++ test/t/float.rb | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index e0fac4d90..385de49bd 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -1,3 +1,4 @@ +$undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 @@ -136,6 +137,25 @@ def _assert_include(affirmed, collection, obj, msg = nil) assert_true(ret, msg, diff) end +def assert_predicate(*args); _assert_predicate(true, *args) end +def assert_not_predicate(*args); _assert_predicate(false, *args) end +def _assert_predicate(affirmed, obj, op, msg = nil) + unless ret = obj.__send__(op) == affirmed + diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}." + end + assert_true(ret, msg, diff) +end + +def assert_operator(*args); _assert_operator(true, *args) end +def assert_not_operator(*args); _assert_operator(false, *args) end +def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) + return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + unless ret = obj1.__send__(op, obj2) == affirmed + diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." + end + assert_true(ret, msg, diff) +end + ## # Fails unless +obj+ is a kind of +cls+. def assert_kind_of(cls, obj, msg = nil) diff --git a/test/t/float.rb b/test/t/float.rb index 4e9d347b8..b4eb0bfd6 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do end assert('Float#finite?', '15.2.9.3.9') do - assert_true 3.123456789.finite? - assert_false (1.0 / 0.0).finite? + assert_predicate 3.123456789, :finite? + assert_not_predicate 1.0 / 0.0, :finite? end assert('Float#floor', '15.2.9.3.10') do @@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do nan = 0.0/0.0 assert_raise(FloatDomainError){ nan.round } assert_raise(FloatDomainError){ nan.round(-1) } - assert_true(nan.round(1).nan?) + assert_predicate(nan.round(1), :nan?) end assert('Float#to_f', '15.2.9.3.13') do @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_true (0.0/0.0).nan? - assert_false 0.0.nan? - assert_false (1.0/0.0).nan? - assert_false (-1.0/0.0).nan? + assert_predicate 0.0/0.0, :nan? + assert_not_predicate 0.0, :nan? + assert_not_predicate 1.0/0.0, :nan? + assert_not_predicate -1.0/0.0, :nan? end assert('Float#<<') do @@ -240,9 +240,9 @@ assert('Float#to_s') do end assert('Float#eql?') do - assert_true(5.0.eql?(5.0)) - assert_false(5.0.eql?(5)) - assert_false(5.0.eql?("5.0")) + assert_operator(5.0, :eql?, 5.0) + assert_not_operator(5.0, :eql?, 5) + assert_not_operator(5.0, :eql?, "5.0") end end # const_defined?(:Float) -- cgit v1.2.3 From cc7f9190ba93ef45bf85a7278dffe6326cf620a3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 20:45:38 +0900 Subject: Fix name assignment to frozen anonymous class/module Fix the following issues: A = Class.new.freeze #=> FrozenError Module.new::B = Class.new.freeze #=> FrozenError String::B = Module.new.freeze #=> FrozenError --- include/mruby/variable.h | 1 + src/class.c | 6 +++--- src/variable.c | 21 ++++++++++++--------- test/t/module.rb | 4 ++++ 4 files changed, 20 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index ba6037959..ff01e5cc8 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -117,6 +117,7 @@ MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_ MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); +void mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); diff --git a/src/class.c b/src/class.c index d6efdbdc4..77ff04437 100644 --- a/src/class.c +++ b/src/class.c @@ -66,15 +66,15 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } static void diff --git a/src/variable.c b/src/variable.c index 983fe52f7..e859f02bf 100644 --- a/src/variable.c +++ b/src/variable.c @@ -341,21 +341,24 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -MRB_API void -mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t; - - mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } - t = obj->iv; - iv_put(mrb, t, sym, v); + iv_put(mrb, obj->iv, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); } +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} + /* Iterates over the instance variable table. */ MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) @@ -385,10 +388,10 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (mrb_nil_p(o)) { if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); } else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); } } } diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..f4999019a 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -653,6 +653,10 @@ assert('Module#to_s') do assert_match "#", Module.new.to_s assert_match "#", Class.new.to_s + + assert_equal "FrozenClassToS", (FrozenClassToS = Class.new.freeze).to_s + assert_equal "Outer::A", (Outer::A = Module.new.freeze).to_s + assert_match "#::A", (Module.new::A = Class.new.freeze).to_s end assert('Module#inspect') do -- cgit v1.2.3 From 9f4147f28e9319a55ff7e865355fd7e70ff0aa73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 21:02:42 +0900 Subject: Fix "ambiguous first argument" warning in `test/t/float.rb` --- test/t/float.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/t/float.rb b/test/t/float.rb index b4eb0bfd6..63bf83f40 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -178,10 +178,10 @@ assert('Float#divmod') do end assert('Float#nan?') do - assert_predicate 0.0/0.0, :nan? - assert_not_predicate 0.0, :nan? - assert_not_predicate 1.0/0.0, :nan? - assert_not_predicate -1.0/0.0, :nan? + assert_predicate(0.0/0.0, :nan?) + assert_not_predicate(0.0, :nan?) + assert_not_predicate(1.0/0.0, :nan?) + assert_not_predicate(-1.0/0.0, :nan?) end assert('Float#<<') do -- cgit v1.2.3 From 4720648137f2698cceb635c251475dec645cd598 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 24 Apr 2019 21:05:44 +0900 Subject: Fix modiying class variable to frozen class/module --- mrbgems/mruby-metaprog/test/metaprog.rb | 8 +++++++- src/variable.c | 2 ++ test/t/class.rb | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1262c9945..0abeb90a6 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -171,7 +171,6 @@ assert('Module#class_variable_set', '15.2.2.4.18') do @@foo end end - assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99) assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101) assert_true Test4ClassVariableSet.class_variables.include? :@@cv @@ -180,6 +179,13 @@ assert('Module#class_variable_set', '15.2.2.4.18') do %w[@@ @@1 @@x= @x @ x 1].each do |n| assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } end + + m = Module.new.freeze + assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) } + + parent = Class.new{ class_variable_set(:@@a, nil) }.freeze + child = Class.new(parent) + assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) } end assert('Module#class_variables', '15.2.2.4.19') do diff --git a/src/variable.c b/src/variable.c index 983fe52f7..c4c9d369f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -671,6 +671,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)c); return; @@ -698,6 +699,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } diff --git a/test/t/class.rb b/test/t/class.rb index 290ecf74a..0c95677fc 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -433,6 +433,25 @@ assert('overriding class variable with a module (#3235)') do end end +assert('class variable for frozen class/module') do + module CVarForFrozenModule + freeze + assert_raise(FrozenError) { @@cv = 1 } + end + + class CVarForFrozenClassA + @@a = nil + freeze + end + class CVarForFrozenClassB < CVarForFrozenClassA + def a=(v) + @@a = v + end + end + b = CVarForFrozenClassB.new + assert_raise(FrozenError) { b.a = 1 } +end + assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } -- cgit v1.2.3 From 8fa3995a1a02e9014ce01351e0260bec20ceefd7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 25 Apr 2019 19:48:40 +0900 Subject: Singleton class of frozen object should be frozen Before this patch: p (class << Object.new.freeze; self end).frozen? #=> false sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> false After this patch / Ruby: p (class << Object.new.freeze; self end).frozen? #=> true sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> true --- mrbgems/mruby-metaprog/test/metaprog.rb | 16 ++++++++++++++++ src/class.c | 1 + src/kernel.c | 1 + test/t/class.rb | 7 +++++++ 4 files changed, 25 insertions(+) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 0abeb90a6..3aa1d8732 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -122,6 +122,22 @@ assert('Kernel#define_singleton_method') do assert_equal :singleton_method_ok, o.test_method end +assert('Kernel#singleton_class') do + o1 = Object.new + assert_same(o1.singleton_class, class << o1; self end) + + o2 = Object.new + sc2 = class << o2; self end + assert_same(o2.singleton_class, sc2) + + o3 = Object.new + sc3 = o3.singleton_class + o3.freeze + assert_predicate(sc3, :frozen?) + + assert_predicate(Object.new.freeze.singleton_class, :frozen?) +end + def labeled_module(name, &block) Module.new do (class <flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; } static mrb_value diff --git a/src/kernel.c b/src/kernel.c index d9a1d36ce..45bca7558 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -438,6 +438,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) struct RBasic *b = mrb_basic_ptr(self); if (!MRB_FROZEN_P(b)) { MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); } } return self; diff --git a/test/t/class.rb b/test/t/class.rb index 0c95677fc..e2839111c 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -356,6 +356,13 @@ assert('singleton tests') do end end end if Object.const_defined?(:Float) + + o = Object.new + sc = class << o; self end + o.freeze + assert_predicate(sc, :frozen?) + + assert_predicate(class << Object.new.freeze; self end, :frozen?) end assert('clone Class') do -- cgit v1.2.3 From 1fb635ac03d3948898623126a8b3d7705e9cdb0f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 26 Apr 2019 21:36:29 +0900 Subject: Add `assert_raise_with_message` and `assert_raise_with_message_pattern` --- test/assert.rb | 36 ++++++++++++++++++++++++++++++------ test/t/kernel.rb | 10 ++++------ test/t/module.rb | 24 +++++++++++++++++------- 3 files changed, 51 insertions(+), 19 deletions(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index 121bd0a8e..da313bf6a 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -6,13 +6,17 @@ $skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) +# For bintest on Ruby unless RUBY_ENGINE == "mruby" - # For bintest on Ruby def t_print(*args) print(*args) $stdout.flush nil end + + def _str_match?(pattern, str) + File.fnmatch?(pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH) + end end ## @@ -180,10 +184,7 @@ end def assert_match(*args); _assert_match(true, *args) end def assert_not_match(*args); _assert_match(false, *args) end def _assert_match(affirmed, pattern, str, msg = nil) - receiver, *args = RUBY_ENGINE == "mruby" ? - [self, :_str_match?, pattern, str] : - [File, :fnmatch?, pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH] - unless ret = !receiver.__send__(*args) == !affirmed + unless ret = _str_match?(pattern, str) == affirmed diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}." end assert_true(ret, msg, diff) @@ -217,8 +218,9 @@ def assert_raise(*exc) exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc begin yield - rescue *exc + rescue *exc => e pass + e rescue Exception => e diff = " #{exc} exception expected, not\n" \ " Class: <#{e.class}>\n" \ @@ -243,6 +245,28 @@ def assert_nothing_raised(msg = nil) end end +def assert_raise_with_message(*args, &block) + _assert_raise_with_message(:plain, *args, &block) +end +def assert_raise_with_message_pattern(*args, &block) + _assert_raise_with_message(:pattern, *args, &block) +end +def _assert_raise_with_message(type, exc, exp_msg, msg = nil, &block) + e = msg ? assert_raise(exc, msg, &block) : assert_raise(exc, &block) + e ? ($mrbtest_assert_idx -= 1) : (return e) + + err_msg = e.message + unless ret = type == :pattern ? _str_match?(exp_msg, err_msg) : exp_msg == err_msg + diff = " Expected Exception(#{exc}) was raised, but the message doesn't match.\n" + if type == :pattern + diff += " Expected #{exp_msg.inspect} to match #{err_msg.inspect}." + else + diff += assertion_diff(exp_msg, err_msg) + end + end + assert_true(ret, msg, diff) +end + def pass assert_true(true) end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7fc8cd2e7 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -346,17 +346,15 @@ assert('Kernel#method_missing', '15.3.1.3.30') do end end no_super_test = NoSuperMethodTestClass.new - begin + msg = "undefined method 'no_super_method_named_this'" + assert_raise_with_message(NoMethodError, msg) do no_super_test.no_super_method_named_this - rescue NoMethodError => e - assert_equal "undefined method 'no_super_method_named_this'", e.message end a = String.new - begin + msg = "undefined method 'no_method_named_this'" + assert_raise_with_message(NoMethodError, msg) do a.no_method_named_this - rescue NoMethodError => e - assert_equal "undefined method 'no_method_named_this'", e.message end end diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..5c659f149 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -21,6 +21,14 @@ def labeled_class(name, supklass = Object, &block) end end +def assert_uninitialized_const(&block) + assert_raise_with_message_pattern(NameError, "uninitialized constant *", &block) +end + +def assert_wrong_const_name(&block) + assert_raise_with_message_pattern(NameError, "wrong constant name *", &block) +end + assert('Module', '15.2.2') do assert_equal Class, Module.class end @@ -221,7 +229,7 @@ assert('Module#const_defined?', '15.2.2.4.20') do assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined) assert_false Test4ConstDefined.const_defined?(:NotExisting) - assert_raise(NameError){ Test4ConstDefined.const_defined?(:wrong_name) } + assert_wrong_const_name{ Test4ConstDefined.const_defined?(:wrong_name) } end assert('Module#const_get', '15.2.2.4.21') do @@ -234,9 +242,9 @@ assert('Module#const_get', '15.2.2.4.21') do assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet") assert_raise(TypeError){ Test4ConstGet.const_get(123) } - assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } - assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } - assert_raise(NameError){ Test4ConstGet.const_get(:wrong_name) } + assert_uninitialized_const{ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } + assert_uninitialized_const{ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } + assert_wrong_const_name{ Test4ConstGet.const_get(:wrong_name) } end assert('Module#const_set', '15.2.2.4.23') do @@ -247,7 +255,7 @@ assert('Module#const_set', '15.2.2.4.23') do assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23) assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet) ["", "wrongNAME", "Wrong-Name"].each do |n| - assert_raise(NameError) { Test4ConstSet.const_set(n, 1) } + assert_wrong_const_name { Test4ConstSet.const_set(n, 1) } end end @@ -258,9 +266,11 @@ assert('Module#remove_const', '15.2.2.4.40') do assert_equal 23, Test4RemoveConst.remove_const(:ExistingConst) assert_false Test4RemoveConst.const_defined?(:ExistingConst) - assert_raise(NameError) { Test4RemoveConst.remove_const(:NonExistingConst) } + assert_raise_with_message_pattern(NameError, "constant * not defined") do + Test4RemoveConst.remove_const(:NonExistingConst) + end %i[x X!].each do |n| - assert_raise(NameError) { Test4RemoveConst.remove_const(n) } + assert_wrong_const_name { Test4RemoveConst.remove_const(n) } end end -- cgit v1.2.3 From 4bf6b8c136ecd6b4bf78e9a66c21943f3f8ab506 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:34:41 +0900 Subject: Refine the default values of `flunk` The default message for the second argument should be set to the first argument because only one argument is normally specified. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index 121bd0a8e..a9bbc9a05 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -247,7 +247,7 @@ def pass assert_true(true) end -def flunk(msg = nil, diff = "Epic Fail!") +def flunk(msg = "Epic Fail!", diff = "") assert_true(false, msg, diff) end -- cgit v1.2.3 From 0692f7916cc9865e276a58812186cac7f02dc042 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 3 May 2019 13:39:19 +0900 Subject: Simplify conversion process for `i` in `mrb_get_args()` --- src/class.c | 24 +----------------------- test/t/string.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 27 deletions(-) (limited to 'test') diff --git a/src/class.c b/src/class.c index 254f5b005..2cabc820e 100644 --- a/src/class.c +++ b/src/class.c @@ -838,29 +838,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } diff --git a/test/t/string.rb b/test/t/string.rb index e563db55a..e5b001366 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,11 +37,14 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_raise(ArgumentError) do - 'a' * -1 - end + assert_equal 'aa', 'a' * 2.1 + assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(RangeError) { '' * 1e30 } + assert_raise(RangeError) { '' * Float::INFINITY } + assert_raise(RangeError) { '' * Float::NAN } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } end - assert('String#[]', '15.2.10.5.6') do # length of args is 1 a = 'abc'[0] -- cgit v1.2.3 From a97a455c031c77f01eaae85ce683e9c1346eb8c9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 27 May 2019 20:51:47 +0900 Subject: Use `$undefined.equal?(obj2)` instead of `obj2 == $undefined` in `assert.rb` In case `obj2.==` is broken. --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index a9bbc9a05..5e2e104b3 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -149,7 +149,7 @@ end def assert_operator(*args); _assert_operator(true, *args) end def assert_not_operator(*args); _assert_operator(false, *args) end def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil) - return _assert_predicate(affirmed, obj1, op, msg) if obj2 == $undefined + return _assert_predicate(affirmed, obj1, op, msg) if $undefined.equal?(obj2) unless ret = obj1.__send__(op, obj2) == affirmed diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}." end -- cgit v1.2.3 From dc1905e1bd8af679c639a67a6787fc41a2612603 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 5 Jun 2019 18:59:48 +0900 Subject: Fix missing assertions in `test/t/module.rb` --- test/t/module.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/t/module.rb b/test/t/module.rb index f4999019a..3bb9735df 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -684,8 +684,8 @@ assert('Issue 1467') do include M1 end - C1.new - C2.new + assert_kind_of(M1, C1.new) + assert_kind_of(M1, C2.new) end assert('clone Module') do @@ -699,7 +699,7 @@ assert('clone Module') do include M1.clone end - B.new.foo + assert_true(B.new.foo) end assert('Module#module_function') do -- cgit v1.2.3 From 4b83fe8b04f61e62d851648c0fe95e8e575181d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 7 Jun 2019 22:02:43 +0900 Subject: Remove `Kernel#global_variables` from core This method is defined in `mruby-metaprog` gem. --- mrbgems/mruby-metaprog/src/metaprog.c | 2 +- mrbgems/mruby-metaprog/test/metaprog.rb | 12 ++++++++++++ src/kernel.c | 1 - test/t/kernel.rb | 15 --------------- 4 files changed, 13 insertions(+), 17 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index e57d10d8d..43d27f4dc 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -686,7 +686,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *krn = mrb->kernel_module; struct RClass *mod = mrb->module_class; - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 3aa1d8732..329580abc 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -99,6 +99,18 @@ assert('Kernel#singleton_methods', '15.3.1.3.45') do assert_equal singleton_methods.class, Array end +assert('Kernel.global_variables', '15.3.1.2.4') do + assert_equal Array, Kernel.global_variables.class +end + +assert('Kernel#global_variables', '15.3.1.3.14') do + variables = global_variables + assert_equal Array, variables.class + 1.upto(9) do |i| + assert_equal variables.include?(:"$#{i}"), true + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b diff --git a/src/kernel.c b/src/kernel.c index 349e71cb8..a3c2d2ec6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -783,7 +783,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7f6e6c58d 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -31,10 +31,6 @@ end # Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3' -assert('Kernel.global_variables', '15.3.1.2.4') do - assert_equal Array, Kernel.global_variables.class -end - assert('Kernel.iterator?', '15.3.1.2.5') do assert_false Kernel.iterator? end @@ -266,10 +262,6 @@ assert('Kernel#frozen?') do assert_true 0.0.frozen? end -assert('Kernel#global_variables', '15.3.1.3.14') do - assert_equal Array, global_variables.class -end - assert('Kernel#hash', '15.3.1.3.15') do assert_equal hash, hash end @@ -488,13 +480,6 @@ assert('Kernel#respond_to_missing?') do assert_false Test4RespondToMissing.new.respond_to?(:no_method) end -assert('Kernel#global_variables') do - variables = global_variables - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end -end - assert('stack extend') do def recurse(count, stop) return count if count > stop -- cgit v1.2.3 From 2e160f53dbd69598ec6a3ee8a15f85b4cf5168cf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 8 Jun 2019 22:32:19 +0900 Subject: Remove "Check the usage of a NUL character" test Because there is not assertion in this test and NUL character literal is used in other tests. --- test/t/string.rb | 4 ---- 1 file changed, 4 deletions(-) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index e5b001366..9817dd188 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -694,10 +694,6 @@ assert('String interpolation (mrb_str_concat for shared strings)') do assert_equal "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:", "#{a}:" end -assert('Check the usage of a NUL character') do - "qqq\0ppp" -end - assert('String#bytes') do str1 = "hello" bytes1 = [104, 101, 108, 108, 111] -- cgit v1.2.3 From ffb700dea0a23930e4f620cf5ff9855efa709f9c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 9 Jun 2019 18:27:28 +0900 Subject: Fix missing assertions in `test/t/syntax.rb` --- test/t/syntax.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 603547c7c..afb735e7f 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -423,10 +423,11 @@ assert('parenthesed do-block in cmdarg') do end assert('method definition in cmdarg') do - if false + result = class MethodDefinitionInCmdarg + def self.bar(arg); arg end bar def foo; self.each do end end end - true + assert_equal(:foo, result) end assert('optional argument in the rhs default expressions') do -- cgit v1.2.3 From 030dd6655e47dad4af4b48a74646712c00684698 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 16 Jun 2019 20:43:23 +0900 Subject: Fix cvar, ivar, const and method can be removed to frozen object --- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 8 ++++++-- src/variable.c | 1 + test/t/kernel.rb | 1 + test/t/module.rb | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 43d27f4dc..0d207ef41 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -641,6 +641,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_value *argv; mrb_get_args(mrb, "*", &argv, &argc); + mrb_check_frozen(mrb, mrb_obj_ptr(mod)); while (argc--) { remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); argv++; diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 685fdf196..46b98d0ed 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -298,6 +298,9 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_raise(NameError) do Test4RemoveClassVariable.remove_class_variable(:@v) end + assert_raise(FrozenError) do + Test4RemoveClassVariable.freeze.remove_class_variable(:@@cv) + end end assert('Module#remove_method', '15.2.2.4.41') do @@ -305,9 +308,9 @@ assert('Module#remove_method', '15.2.2.4.41') do class Parent def hello end - end + end - class Child < Parent + class Child < Parent def hello end end @@ -317,6 +320,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_same klass, klass.class_eval{ remove_method :hello } assert_true klass.instance_methods.include? :hello assert_false klass.instance_methods(false).include? :hello + assert_raise(FrozenError) { klass.freeze.remove_method :m } end assert('Module.nesting', '15.2.2.2.2') do diff --git a/src/variable.c b/src/variable.c index 779f206dc..23d900b7d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,6 +521,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 7f6e6c58d..950442351 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -404,6 +404,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_equal nil, tri.var assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } + assert_raise(FrozenError) { tri.freeze.remove } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' diff --git a/test/t/module.rb b/test/t/module.rb index 3bb9735df..571f4759d 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -262,6 +262,7 @@ assert('Module#remove_const', '15.2.2.4.40') do %i[x X!].each do |n| assert_raise(NameError) { Test4RemoveConst.remove_const(n) } end + assert_raise(FrozenError) { Test4RemoveConst.freeze.remove_const(:A) } end assert('Module#const_missing', '15.2.2.4.22') do -- cgit v1.2.3 From c43ff6fa4063d22db391ab1818b121110ca520bf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 21 Jun 2019 22:02:29 +0900 Subject: Move `Kernel#__send__` test to core from `mruby-metaprog` --- mrbgems/mruby-metaprog/test/metaprog.rb | 14 -------------- test/t/kernel.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 46b98d0ed..1e1d4ff26 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -1,17 +1,3 @@ -assert('Kernel#__send__', '15.3.1.3.4') do - # test with block - l = __send__(:lambda) do - true - end - - assert_true l.call - assert_equal Proc, l.class - # test with argument - assert_true __send__(:respond_to?, :nil?) - # test without argument and without block - assert_equal String, __send__(:to_s).class -end - assert('Kernel#send', '15.3.1.3.44') do # test with block l = send(:lambda) do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 950442351..103660f53 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -88,6 +88,20 @@ assert('Kernel#__id__', '15.3.1.3.3') do assert_equal Fixnum, __id__.class end +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal String, __send__(:to_s).class +end + assert('Kernel#block_given?', '15.3.1.3.6') do def bg_try(&b) if block_given? -- cgit v1.2.3 From 5af8a9777be82838b65c5b84bb2758f5395df998 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:08 +0900 Subject: Add test for one UTF-8 charactor --- test/t/string.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index 9817dd188..7ef236dbe 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -479,6 +479,7 @@ assert('String#reverse(UTF-8)', '15.2.10.5.29') do assert_equal 'こんにちは世界!', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse + assert_equal 'あ', 'あ'.reverse end if UTF8STRING assert('String#reverse!', '15.2.10.5.30') do @@ -495,6 +496,10 @@ assert('String#reverse!(UTF-8)', '15.2.10.5.30') do assert_equal '!界世はちにんこ', a assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse! + + b = 'あ' + b.reverse! + assert_equal 'あ', b end if UTF8STRING assert('String#rindex', '15.2.10.5.31') do -- cgit v1.2.3 From ad8473bd66c0dd622146e226f281909248b47305 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 27 Jun 2019 18:47:48 +0900 Subject: Add modification tests for immediate value --- mrbgems/mruby-metaprog/test/metaprog.rb | 4 ++++ test/t/kernel.rb | 1 + 2 files changed, 5 insertions(+) (limited to 'test') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1e1d4ff26..30b75bd60 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -44,6 +44,8 @@ assert('Kernel#instance_variable_set', '15.3.1.3.22') do %w[@6 @% @@a @ a].each do |n| assert_raise(NameError) { o.instance_variable_set(n, 1) } end + assert_raise(FrozenError) { o.freeze.instance_variable_set(:@a, 2) } + assert_raise(FrozenError, ArgumentError) { nil.instance_variable_set(:@a, 2) } end assert('Kernel#instance_variables', '15.3.1.3.23') do @@ -121,6 +123,8 @@ assert('Kernel#define_singleton_method') do end assert_equal :test_method, ret assert_equal :singleton_method_ok, o.test_method + assert_raise(TypeError) { 2.define_singleton_method(:f){} } + assert_raise(FrozenError) { [].freeze.define_singleton_method(:f){} } end assert('Kernel#singleton_class') do diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 103660f53..1e48069f2 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -419,6 +419,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } assert_raise(FrozenError) { tri.freeze.remove } + assert_raise(FrozenError, NameError) { :a.remove_instance_variable(:@v) } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' -- cgit v1.2.3 From bc3176da630e3e055d58aa065ff897aec66df280 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:26:29 +0900 Subject: Use `__ENCODING__` in tests It cannot be used for `String#size` test if judging whether or not `MRB_UTF8_STRING` is defined by result of `String#size`. --- mrbgems/mruby-string-ext/test/string.rb | 2 +- mrbgems/mruby-symbol-ext/test/symbol.rb | 2 +- test/t/string.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index bf633bcef..9a324c46d 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -2,7 +2,7 @@ ## # String(Ext) Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String#getbyte') do str1 = "hello" diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 61ecad247..db686e5f4 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -14,7 +14,7 @@ end assert("Symbol##{n}") do assert_equal 5, :hello.__send__(n) assert_equal 4, :"aA\0b".__send__(n) - if "あ".size == 1 # enable MRB_UTF8_STRING? + if __ENCODING__ == "UTF-8" assert_equal 8, :"こんにちは世界!".__send__(n) assert_equal 4, :"aあ\0b".__send__(n) else diff --git a/test/t/string.rb b/test/t/string.rb index 7ef236dbe..81699f17e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -2,7 +2,7 @@ ## # String ISO Test -UTF8STRING = ("\343\201\202".size == 1) +UTF8STRING = __ENCODING__ == "UTF-8" assert('String', '15.2.10') do assert_equal Class, String.class -- cgit v1.2.3 From 5f9034e4283ccaa99c929a36e2cfbb465e8b31b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Jun 2019 22:24:58 +0900 Subject: Nested `assert` for mrbtest When nesting `assert` used in test, it is indented and displayed. Assertion numbers are concatenated by `"-"` at this time. The purpose is to match the apparent numbers when failing with `assert_mruby` which is defined by `mrbgems/mruby-bin-mruby/bintest/mruby.rb` for example. Child assertions "skip" and "info" are reported as parent assertions "info" and `$ok_test += 1`. The child assertions "ko" and "crash" are reported as the parent assertion "ko" and `$ko_test += 1`. When child assertions are mixed, "ko" takes precedence. Incompatibility: - `$mrbtest_assert_idx` takes `nil` or an integer array object. So far it was `nil` or an integer. - `$asserts` points to the top of the internal stack in the `assert`. - `$mrbtest_assert` points to the top of the internal stack in `assert`. --- test/assert.rb | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index 5e2e104b3..c493cbbc0 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -15,6 +15,36 @@ unless RUBY_ENGINE == "mruby" end end +class Array + def _assertion_join + join("-") + end +end + +class String + def _assertion_indent(indent) + indent = indent.to_s + off = 0 + str = self + while nl = index("\n", off) + nl += 1 + nl += 1 while slice(nl) == "\n" + break if nl >= size + str = indent.dup if off == 0 + str += slice(off, nl - off) + indent + off = nl + end + + if off == 0 + str = indent + self + else + str += slice(off..-1) + end + + str + end +end + ## # Create the assertion in a readable way def assertion_string(err, str, iso=nil, e=nil, bt=nil) @@ -22,14 +52,14 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil) msg += " [#{iso}]" if iso && !iso.empty? msg += " => #{e}" if e && !e.to_s.empty? msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})" - if $mrbtest_assert && $mrbtest_assert.size > 0 + if $mrbtest_assert $mrbtest_assert.each do |idx, assert_msg, diff| msg += "\n - Assertion[#{idx}]" msg += " #{assert_msg}." if assert_msg && !assert_msg.empty? msg += "\n#{diff}" if diff && !diff.empty? end end - msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt + msg += "\nbacktrace:\n #{bt.join("\n ")}" if bt msg end @@ -44,13 +74,35 @@ end def assert(str = 'Assertion failed', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin + $mrbtest_child_noassert ||= [0] + $mrbtest_child_noassert << 0 + parent_asserts = $asserts + $asserts = [] + parent_mrbtest_assert = $mrbtest_assert $mrbtest_assert = [] - $mrbtest_assert_idx = 0 + + if $mrbtest_assert_idx && !$mrbtest_assert_idx.empty? + $mrbtest_assert_idx[-1] += 1 + $mrbtest_assert_idx << 0 + else + $mrbtest_assert_idx = [0] + class << $mrbtest_assert_idx + alias to_s _assertion_join + end + end + yield - if($mrbtest_assert.size > 0) - $asserts.push(assertion_string('Fail: ', str, iso)) - $ko_test += 1 - t_print('F') + if $mrbtest_assert.size > 0 + if $mrbtest_assert.size == $mrbtest_child_noassert[-1] + $asserts.push(assertion_string('Info: ', str, iso)) + $mrbtest_child_noassert[-2] += 1 + $ok_test += 1 + t_print('.') + else + $asserts.push(assertion_string('Fail: ', str, iso)) + $ko_test += 1 + t_print('F') + end else $ok_test += 1 t_print('.') @@ -58,6 +110,7 @@ def assert(str = 'Assertion failed', iso = '') rescue MRubyTestSkip => e $asserts.push(assertion_string('Skip: ', str, iso, e)) $skip_test += 1 + $mrbtest_child_noassert[-2] += 1 t_print('?') rescue Exception => e bt = e.backtrace if $mrbtest_verbose @@ -65,7 +118,25 @@ def assert(str = 'Assertion failed', iso = '') $kill_test += 1 t_print('X') ensure - $mrbtest_assert = nil + if $mrbtest_assert_idx.size > 1 + $asserts.each do |mesg| + idx = $mrbtest_assert_idx[0..-2]._assertion_join + mesg = mesg._assertion_indent(" ") + + # Give `mesg` as a `diff` argument to avoid adding extra periods. + parent_mrbtest_assert << [idx, nil, mesg] + end + else + parent_asserts.concat $asserts + end + $asserts = parent_asserts + + $mrbtest_assert = parent_mrbtest_assert + $mrbtest_assert_idx.pop + $mrbtest_assert_idx = nil if $mrbtest_assert_idx.empty? + $mrbtest_child_noassert.pop + + nil end t_print("\n") if $mrbtest_verbose end @@ -76,11 +147,11 @@ def assertion_diff(exp, act) end def assert_true(obj, msg = nil, diff = nil) - if $mrbtest_assert - $mrbtest_assert_idx += 1 + if $mrbtest_assert_idx && $mrbtest_assert_idx.size > 0 + $mrbtest_assert_idx[-1] += 1 unless obj == true diff ||= " Expected #{obj.inspect} to be true." - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + $mrbtest_assert.push([$mrbtest_assert_idx.to_s, msg, diff]) end end obj -- cgit v1.2.3 From 40030a5dbc2b76bbd9563cdfc6389ab672312b70 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 21:58:53 +0900 Subject: Add test for `String#[]=` --- test/t/string.rb | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index 81699f17e..87d60ed72 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -209,6 +209,56 @@ assert('String#[]=') do assert_raise(TypeError) { 'a'[0, 1] = 1 } end +assert('String[]=(UTF-8)') do + a = "➀➁➂➃➄" + a[3] = "⚃" + assert_equal "➀➁➂⚃➄", a + + b = "➀➁➂➃➄" + b[3, 0] = "⛄" + assert_equal "➀➁➂⛄➃➄", b + + c = "➀➁➂➃➄" + c[3, 2] = "⚃⚄" + assert_equal "➀➁➂⚃⚄", c + + d = "➀➁➂➃➄" + d[5] = "⛄" + assert_equal "➀➁➂➃➄⛄", d + + e = "➀➁➂➃➄" + e[5, 0] = "⛄" + assert_equal "➀➁➂➃➄⛄", e + + f = "➀➁➂➃➄" + f[5, 2] = "⛄" + assert_equal "➀➁➂➃➄⛄", f + + g = "➀➁➂➃➄" + assert_raise(IndexError) { g[6] = "⛄" } + + h = "➀➁➂➃➄" + assert_raise(IndexError) { h[6, 0] = "⛄" } + + i = "➀➁➂➃➄" + assert_raise(IndexError) { i[6, 2] = "⛄" } + + j = "➀➁➂➃➄" + j["➃"] = "⚃" + assert_equal "➀➁➂⚃➄", j + + k = "➀➁➂➃➄" + assert_raise(IndexError) { k["⛄"] = "⛇" } + + l = "➀➁➂➃➄" + assert_nothing_raised { l["➂"] = "" } + assert_equal "➀➁➃➄", l + + m = "➀➁➂➃➄" + assert_raise(TypeError) { m["➂"] = nil } + assert_equal "➀➁➂➃➄", m +end if UTF8STRING + assert('String#capitalize', '15.2.10.5.7') do a = 'abc' a.capitalize -- cgit v1.2.3 From 97c9e6b00032cd8a7132b43911c05e44732a4c56 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Jun 2019 14:46:38 +0900 Subject: Fix `include`, `prepend` and `extend` to frozen object --- src/class.c | 5 +++-- test/t/kernel.rb | 3 +++ test/t/module.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/src/class.c b/src/class.c index 373f2aec7..1064870a8 100644 --- a/src/class.c +++ b/src/class.c @@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 1e48069f2..ecfb863a8 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do assert_true a.respond_to?(:test_method) assert_false b.respond_to?(:test_method) + + assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) } + assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) } end assert('Kernel#extend works on toplevel', '15.3.1.3.13') do diff --git a/test/t/module.rb b/test/t/module.rb index 571f4759d..7f869bf1f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do end assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) + assert_raise(FrozenError) { Module.new.append_features Class.new.freeze } end assert('Module#attr NameError') do @@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end +assert('Module#extend_object', '15.2.2.4.25') do + cls = Class.new + mod = Module.new { def foo; end } + a = cls.new + b = cls.new + mod.extend_object(b) + assert_false a.respond_to?(:foo) + assert_true b.respond_to?(:foo) + assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) } + assert_raise(FrozenError, TypeError) { mod.extend_object(1) } +end + assert('Module#include', '15.2.2.4.27') do module Test4Include Const4Include = 42 @@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do assert_equal 42, Test4Include2.const_get(:Const4Include) assert_equal Test4Include2, Test4Include2.include_result + assert_raise(FrozenError) { Module.new.freeze.include Test4Include } end assert('Module#include?', '15.2.2.4.28') do @@ -398,6 +412,15 @@ assert('Module#define_method') do end end +assert 'Module#prepend_features' do + mod = Module.new { def m; :mod end } + cls = Class.new { def m; :cls end } + assert_equal :cls, cls.new.m + mod.prepend_features(cls) + assert_equal :mod, cls.new.m + assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) } +end + # @!group prepend assert('Module#prepend') do module M0 @@ -632,6 +655,10 @@ end # end # end; #end + + assert 'Module#prepend to frozen class' do + assert_raise(FrozenError) { Class.new.freeze.prepend Module.new } + end # @!endgroup prepend assert('Module#to_s') do -- cgit v1.2.3 From 32c2aa10c79e37c53411b1d693c6c8d010fba7bb Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 7 Jul 2019 22:10:32 +0900 Subject: Fix `Numeric#step` to infinity; ref. #4555 --- mrblib/numeric.rb | 8 ++--- test/t/numeric.rb | 88 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 27 deletions(-) (limited to 'test') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 5a3c5eb58..5926518d5 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -105,14 +105,14 @@ module Integral return to_enum(:step, num, step) unless block i = __coerce_step_counter(num, step) - if num == nil + if num == self || step.infinite? + block.call(i) if step > 0 && i <= (num||i) || step < 0 && i >= (num||-i) + elsif num == nil while true block.call(i) i += step end - return self - end - if step > 0 + elsif step > 0 while i <= num block.call(i) i += step diff --git a/test/t/numeric.rb b/test/t/numeric.rb index d73dfdb61..bb95f8ef3 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -1,6 +1,19 @@ ## # Numeric ISO Test +def assert_step(exp, receiver, args, inf: false) + act = [] + ret = receiver.step(*args) do |i| + act << i + break if inf && exp.size == act.size + end + expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" + assert do + assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) + assert_same(receiver, ret, "#{expr}: return value") unless inf + end +end + assert('Numeric', '15.2.7') do assert_equal(Class, Numeric.class) end @@ -42,31 +55,60 @@ assert('Numeric#**') do end assert('Numeric#step') do - assert_step = ->(exp, receiver, args) do - inf = !args[0] - act = [] - ret = receiver.step(*args) do |i| - act << i - break if inf && exp.size == act.size - end - expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) - assert_same(receiver, ret, "#{expr}: return value") unless inf - end - assert_raise(ArgumentError) { 1.step(2, 0) { break } } - assert_step.([2, 3, 4], 2, [4]) - assert_step.([10, 8, 6, 4, 2], 10, [1, -2]) - assert_step.([], 2, [1, 3]) - assert_step.([], -2, [-1, -3]) - assert_step.([10, 11, 12, 13], 10, []) - assert_step.([10, 7, 4], 10, [nil, -3]) + assert_step([2, 3, 4], 2, [4]) + assert_step([10, 8, 6, 4, 2], 10, [1, -2]) + assert_step([], 2, [1, 3]) + assert_step([], -2, [-1, -3]) + assert_step([10, 11, 12, 13], 10, [], inf: true) + assert_step([10, 7, 4], 10, [nil, -3], inf: true) skip unless Object.const_defined?(:Float) + inf = Float::INFINITY assert_raise(ArgumentError) { 1.step(2, 0.0) { break } } - assert_step.([2.0, 3.0, 4.0], 2, [4.0]) - assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) - assert_step.([2.0, 3.0, 4.0], 2.0, [4]) - assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, []) - assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0]) + assert_step([2.0, 3.0, 4.0], 2, [4.0]) + assert_step([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0]) + assert_step([2.0, 3.0, 4.0], 2.0, [4]) + assert_step([10.0, 11.0, 12.0, 13.0], 10.0, [], inf: true) + assert_step([10.0, 7.0, 4.0], 10, [nil, -3.0], inf: true) + assert_step([1.0], 1, [nil, inf]) + assert_step([1.0], 1, [nil, -inf]) + assert_step([1.0], 1, [3, inf]) + assert_step([], 1, [-3, inf]) + assert_step([], 1, [3, -inf]) + assert_step([1.0], 1, [-3, -inf]) + assert_step([1.0], 1, [inf, inf]) + assert_step([], 1, [inf, -inf]) + assert_step([], 1, [-inf, inf]) + assert_step([1.0], 1, [-inf, -inf]) + assert_step([], inf, [2]) + assert_step([], inf, [-2]) + assert_step([], inf, [2, 3]) + assert_step([inf, inf, inf], inf, [2, -3], inf: true) + assert_step([], inf, [2, inf]) + assert_step([inf], inf, [2, -inf]) + assert_step([], inf, [-2, inf]) + assert_step([inf], inf, [-2, -inf]) + assert_step([], inf, [-2, 3]) + assert_step([inf, inf, inf], inf, [-2, -3], inf: true) + assert_step([inf], inf, [inf]) + assert_step([], inf, [-inf]) + assert_step([inf], inf, [inf, inf]) + assert_step([inf], inf, [inf, -inf]) + assert_step([inf], inf, [-inf, -inf]) + assert_step([-inf, -inf, -inf], -inf, [2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [-2], inf: true) + assert_step([-inf, -inf, -inf], -inf, [2, 3], inf: true) + assert_step([], -inf, [2, -3]) + assert_step([-inf], -inf, [2, inf]) + assert_step([], -inf, [2, -inf]) + assert_step([-inf], -inf, [-2, inf]) + assert_step([], -inf, [-2, -inf]) + assert_step([-inf, -inf, -inf], -inf, [-2, 3], inf: true) + assert_step([], -inf, [-2, -3]) + assert_step([-inf, -inf, -inf], -inf, [inf], inf: true) + assert_step([-inf], -inf, [-inf]) + assert_step([-inf], -inf, [inf, inf]) + assert_step([], -inf, [inf, -inf]) + assert_step([-inf], -inf, [-inf, -inf]) end -- cgit v1.2.3 From c8a7d0ab9541a4297d3885842c5fc1343fe5ea99 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 13:13:13 +0900 Subject: Fix the order of "expected" and "actual" in `test/t/range.rb` --- test/t/range.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/t/range.rb b/test/t/range.rb index d71fe8946..106c2866e 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -101,12 +101,12 @@ end assert('Range#dup') do r = (1..3).dup - assert_equal r.begin, 1 - assert_equal r.end, 3 + assert_equal 1, r.begin + assert_equal 3, r.end assert_false r.exclude_end? r = ("a"..."z").dup - assert_equal r.begin, "a" - assert_equal r.end, "z" + assert_equal "a", r.begin + assert_equal "z", r.end assert_true r.exclude_end? end -- cgit v1.2.3 From e4249b1b9e1c568546865287bf367e4501c263de Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 22:00:01 +0900 Subject: Add UTF-8 test for `String#index` --- test/t/string.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index 87d60ed72..cf145f97e 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -468,6 +468,17 @@ assert('String#index', '15.2.10.5.22') do assert_equal nil, "hello".index("", 6) end +assert('String#index(UTF-8)', '15.2.10.5.22') do + assert_equal 0, '⓿➊➋➌➍➎'.index('⓿') + assert_nil '⓿➊➋➌➍➎'.index('➓') + assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', 1) + assert_equal 6, "⓿➊➋➌➍➎".index("", 6) + assert_equal nil, "⓿➊➋➌➍➎".index("", 7) + assert_equal 0, '⓿➊➋➌➍➎'.index("\xe2") + assert_equal nil, '⓿➊➋➌➍➎'.index("\xe3") + assert_equal 6, "\xd1\xd1\xd1\xd1\xd1\xd1⓿➊➋➌➍➎".index('⓿') +end if UTF8STRING + assert('String#initialize', '15.2.10.5.23') do a = '' a.initialize('abc') -- cgit v1.2.3 From b4cdced22fe1f25d8cf6fc499a2e2c9875f17e9e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 18:05:01 +0900 Subject: `Enumerable#detect` {and `#find`} should call `ifnone`; fix #4484 It's an error in ISO specification; 15.3.2.2.4 and 15.3.2.2.7 --- mrblib/enum.rb | 16 +++++++--------- test/t/enumerable.rb | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/mrblib/enum.rb b/mrblib/enum.rb index 9bd74e1c4..fe40b4d27 100644 --- a/mrblib/enum.rb +++ b/mrblib/enum.rb @@ -65,22 +65,20 @@ module Enumerable end ## - # Call the given block for each element - # which is yield by +each+. Return - # +ifnone+ if no block value was true. - # Otherwise return the first block value - # which had was true. + # Return the first element for which + # value from the block is true. If no + # object matches, calls +ifnone+ and + # returns its result. Otherwise returns + # +nil+. # # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) - ret = ifnone self.each{|*val| if block.call(*val) - ret = val.__svalue - break + return val.__svalue end } - ret + ifnone.call unless ifnone.nil? end ## diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb index 652c304da..9e7602db7 100644 --- a/test/t/enumerable.rb +++ b/test/t/enumerable.rb @@ -45,7 +45,7 @@ end assert('Enumerable#detect', '15.3.2.2.4') do assert_equal 1, [1,2,3].detect() { true } - assert_equal 'a', [1,2,3].detect("a") { false } + assert_equal 'a', [1,2,3].detect(->{"a"}) { false } end assert('Array#each_with_index', '15.3.2.2.5') do @@ -64,7 +64,7 @@ end assert('Enumerable#find', '15.3.2.2.7') do assert_equal 1, [1,2,3].find() { true } - assert_equal 'a', [1,2,3].find("a") { false } + assert_equal 'a', [1,2,3].find(->{"a"}) { false } end assert('Enumerable#find_all', '15.3.2.2.8') do -- cgit v1.2.3 From 9d2272ec2ca00e8951a61e2e1f287de04ee7f1c6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 17 Jul 2019 20:09:37 +0900 Subject: Fix `String#[]` test --- test/t/string.rb | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index cf145f97e..af944b359 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -45,44 +45,27 @@ assert('String#*', '15.2.10.5.5') do assert_raise(TypeError) { 'a' * '1' } assert_raise(TypeError) { 'a' * nil } end + assert('String#[]', '15.2.10.5.6') do # length of args is 1 - a = 'abc'[0] - b = 'abc'[-1] - c = 'abc'[10] - d = 'abc'[-10] - e = 'abc'[1.1] + assert_equal 'a', 'abc'[0] + assert_equal 'c', 'abc'[-1] + assert_nil 'abc'[10] + assert_nil 'abc'[-10] + assert_equal 'b', 'abc'[1.1] if Object.const_defined?(:Float) # length of args is 2 - a1 = 'abc'[0, -1] - b1 = 'abc'[10, 0] - c1 = 'abc'[-10, 0] - d1 = 'abc'[0, 0] - e1 = 'abc'[1, 2] - - # args is RegExp - # It will be tested in mrbgems. + assert_nil 'abc'[0, -1] + assert_nil 'abc'[10, 0] + assert_nil 'abc'[-10, 0] + assert_equal '', 'abc'[0, 0] + assert_equal 'bc', 'abc'[1, 2] # args is String - a3 = 'abc'['bc'] - b3 = 'abc'['XX'] - - assert_equal 'a', 'a' - # assert_equal 'c', b - # assert_nil c - # assert_nil d - # assert_equal 'b', e - # assert_nil a1 - # assert_nil b1 - # assert_nil c1 - # assert_equal '', d1 - # assert_equal 'bc', e1 - # assert_equal 'bc', a3 - # assert_nil b3 - - # assert_raise(TypeError) do - # a[nil] - # end + assert_equal 'bc', 'abc'['bc'] + assert_nil 'abc'['XX'] + + assert_raise(TypeError) { 'abc'[nil] } end assert('String#[](UTF-8)', '15.2.10.5.6') do -- cgit v1.2.3 From 9873d5e0b9f1d3be9b2c97a21789ccdbd500e039 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 18 Jul 2019 17:51:02 +0900 Subject: Fix `String#*` test with `MRB_WITHOUT_FLOAT` --- test/t/string.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index af944b359..46cbe6e2a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,13 +37,15 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_equal 'aa', 'a' * 2.1 assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } + + skip unless Object.const_defined?(:Float) + assert_equal 'aa', 'a' * 2.1 assert_raise(RangeError) { '' * 1e30 } assert_raise(RangeError) { '' * Float::INFINITY } assert_raise(RangeError) { '' * Float::NAN } - assert_raise(TypeError) { 'a' * '1' } - assert_raise(TypeError) { 'a' * nil } end assert('String#[]', '15.2.10.5.6') do -- cgit v1.2.3 From 7675fcb5d3e8e19964b46df7c1547e27f4a2bbde Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 20 Jul 2019 22:39:48 +0900 Subject: Fix `Module#dup` to frozen module Before this patch: $ bin/mruby -e 'p Module.new.freeze.dup.frozen?' #=> true After this patch (same as Ruby): $ bin/mruby -e 'p Module.new.freeze.dup.frozen?' #=> false --- src/class.c | 9 +++++++++ src/kernel.c | 1 - test/t/module.rb | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/src/class.c b/src/class.c index 2961284f5..65d21ad4f 100644 --- a/src/class.c +++ b/src/class.c @@ -2077,6 +2077,14 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } +static mrb_value +mrb_mod_dup(mrb_state *mrb, mrb_value self) +{ + mrb_value mod = mrb_obj_clone(mrb, self); + MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod)); + return mod; +} + static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { @@ -2207,6 +2215,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ + mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/kernel.c b/src/kernel.c index a3c2d2ec6..f223be9fc 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -805,5 +805,4 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/test/t/module.rb b/test/t/module.rb index 7f869bf1f..0155ec190 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -400,6 +400,29 @@ end # Not ISO specified +assert('Module#dup') do + module TestModuleDup + @@cvar = :cvar + class << self + attr_accessor :cattr + def cmeth; :cmeth end + end + def cvar; @@cvar end + def imeth; :imeth end + self.cattr = :cattr + end + + m = TestModuleDup.dup + o = Object.include(m).new + assert_equal(:cattr, m.cattr) + assert_equal(:cmeth, m.cmeth) + assert_equal(:cvar, o.cvar) + assert_equal(:imeth, o.imeth) + assert_match("#", m.to_s) + assert_not_predicate(m, :frozen?) + assert_not_predicate(TestModuleDup.freeze.dup, :frozen?) +end + assert('Module#define_method') do c = Class.new { define_method(:m1) { :ok } -- cgit v1.2.3 From cd8fc9bcb81a8e9e7e76413f3132b0515c8bd218 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Jul 2019 01:02:03 +0900 Subject: Resolved conflicts in #4320 --- mrbgems/mruby-test/driver.c | 1 + test/assert.rb | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index 602b76c79..b6c9fab35 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -258,6 +258,7 @@ mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src) TEST_COUNT_PASS(ok_test); TEST_COUNT_PASS(ko_test); TEST_COUNT_PASS(kill_test); + TEST_COUNT_PASS(warning_test); TEST_COUNT_PASS(skip_test); #undef TEST_COUNT_PASS diff --git a/test/assert.rb b/test/assert.rb index c493cbbc0..4641e6657 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -2,6 +2,7 @@ $undefined = Object.new $ok_test = 0 $ko_test = 0 $kill_test = 0 +$warning_test = 0 $skip_test = 0 $asserts = [] $test_start = Time.now if Object.const_defined?(:Time) @@ -103,6 +104,10 @@ def assert(str = 'Assertion failed', iso = '') $ko_test += 1 t_print('F') end + elsif $mrbtest_assert_idx == 0 + $asserts.push(assertion_string('Warn: ', str, iso, 'no assertion')) + $warning_test += 1 + t_print('W') else $ok_test += 1 t_print('.') @@ -332,17 +337,18 @@ def report t_print("#{msg}\n") end - $total_test = $ok_test + $ko_test + $kill_test + $skip_test - t_print("Total: #{$total_test}\n") + $total_test = $ok_test + $ko_test + $kill_test + $warning_test + $skip_test + t_print(" Total: #{$total_test}\n") - t_print(" OK: #{$ok_test}\n") - t_print(" KO: #{$ko_test}\n") - t_print("Crash: #{$kill_test}\n") - t_print(" Skip: #{$skip_test}\n") + t_print(" OK: #{$ok_test}\n") + t_print(" KO: #{$ko_test}\n") + t_print(" Crash: #{$kill_test}\n") + t_print("Warning: #{$warning_test}\n") + t_print(" Skip: #{$skip_test}\n") if Object.const_defined?(:Time) t_time = Time.now - $test_start - t_print(" Time: #{t_time.round(2)} seconds\n") + t_print(" Time: #{t_time.round(2)} seconds\n") end $ko_test == 0 && $kill_test == 0 -- cgit v1.2.3 From ff43b2b97c77812abbcbfe14da4582c6c209be9b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Jul 2019 01:25:58 +0900 Subject: Fixed a conflict between #4407 and #4540 --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index b2d5011ad..58ee4b913 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -329,7 +329,7 @@ def assert_raise_with_message_pattern(*args, &block) end def _assert_raise_with_message(type, exc, exp_msg, msg = nil, &block) e = msg ? assert_raise(exc, msg, &block) : assert_raise(exc, &block) - e ? ($mrbtest_assert_idx -= 1) : (return e) + e ? ($mrbtest_assert_idx[-1]-=1) : (return e) err_msg = e.message unless ret = type == :pattern ? _str_match?(exp_msg, err_msg) : exp_msg == err_msg -- cgit v1.2.3 From 5091d047c0b965c4860e8d47cb95f72687b37a7f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Jul 2019 21:40:58 +0900 Subject: Fix "Warn if assertion is missing inside `assert`"; ref ff43b2b9 --- test/assert.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index 58ee4b913..a63e626cf 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -108,7 +108,7 @@ def assert(str = 'Assertion failed', iso = '') $ko_test += 1 t_print('F') end - elsif $mrbtest_assert_idx == 0 + elsif $mrbtest_assert_idx[-1] == 0 $asserts.push(assertion_string('Warn: ', str, iso, 'no assertion')) $warning_test += 1 t_print('W') -- cgit v1.2.3 From 44381f0a0c306a8c778f546926d3febfdf981b45 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 30 Jul 2019 12:46:24 +0900 Subject: Refine message to `skip` in nested `assert` - I think "Info" is used only to `skip`, so change to "Skip". - Changed the default value of `assert` and specify the argument explicitly at the caller of `assert` because it is unnatural "Assertion failed" is output even though the assertion doesn't fail. == Example: def assert_foo(exp, act) assert do assert_equal exp[0], act[0] assert_equal exp[1], act[1] end end def assert_bar(exp, act) assert do skip end end def assert_baz(exp, act) assert do assert_equal exp, act assert_bar exp, act end end assert 'test#skip_in_nested_assert' do assert_baz 1, 1 end === Before this patch: ?.. Info: test#skip_in_nested_assert (core) - Assertion[1] Info: Assertion failed (core) - Assertion[1-2] Skip: Assertion failed (core) Total: 3 OK: 2 KO: 0 Crash: 0 Warning: 0 Skip: 1 === After this patch: ??? Skip: test#skip_in_nested_assert (core) - Assertion[1] Skip: assert (core) - Assertion[1-2] Skip: assert (core) Total: 3 OK: 0 KO: 0 Crash: 0 Warning: 0 Skip: 3 --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 2 +- mrbgems/mruby-complex/test/complex.rb | 2 +- mrbgems/mruby-io/test/io.rb | 2 +- mrbgems/mruby-pack/test/pack.rb | 2 +- mrbgems/mruby-rational/test/rational.rb | 4 ++-- test/assert.rb | 8 ++++---- test/t/numeric.rb | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 5dbbc5592..e032ff79a 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,7 +3,7 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert do + assert "assert_mruby" do assert_operator(exp_out, :===, out, "standard output") assert_operator(exp_err, :===, err, "standard error") assert_equal(exp_success, stat.success?, "exit success?") diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 5b7c3bfa4..4ae80515b 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,5 +1,5 @@ def assert_complex(real, exp) - assert do + assert "assert_complex" do assert_float real.real, exp.real assert_float real.imaginary, exp.imaginary end diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 1491a4cfe..3aaa109a8 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,7 +5,7 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - assert do + assert "assert_io_open" do fd = IO.sysopen($mrbtest_io_rfname) assert_equal Fixnum, fd.class io1 = IO.__send__(meth, fd) diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 68ef4165f..6832adcc7 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,7 +2,7 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert do + assert "assert_pack" do assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" end diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 11737034b..a8ebb8ea2 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,14 +23,14 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert do + assert "assert_rational" do assert_float exp.numerator, real.numerator assert_float exp.denominator, real.denominator end end def assert_equal_rational(exp, o1, o2) - assert do + assert "assert_equal_rational" do if exp assert_operator(o1, :==, o2) assert_not_operator(o1, :!=, o2) diff --git a/test/assert.rb b/test/assert.rb index 58ee4b913..5ae46ca70 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -76,7 +76,7 @@ end # iso : The ISO reference code of the feature # which will be tested by this # assertion -def assert(str = 'Assertion failed', iso = '') +def assert(str = 'assert', iso = '') t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose begin $mrbtest_child_noassert ||= [0] @@ -99,10 +99,10 @@ def assert(str = 'Assertion failed', iso = '') yield if $mrbtest_assert.size > 0 if $mrbtest_assert.size == $mrbtest_child_noassert[-1] - $asserts.push(assertion_string('Info: ', str, iso)) + $asserts.push(assertion_string('Skip: ', str, iso)) $mrbtest_child_noassert[-2] += 1 - $ok_test += 1 - t_print('.') + $skip_test += 1 + t_print('?') else $asserts.push(assertion_string('Fail: ', str, iso)) $ko_test += 1 diff --git a/test/t/numeric.rb b/test/t/numeric.rb index bb95f8ef3..5b1e79153 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -8,7 +8,7 @@ def assert_step(exp, receiver, args, inf: false) break if inf && exp.size == act.size end expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})" - assert do + assert "assert_step" do assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act)) assert_same(receiver, ret, "#{expr}: return value") unless inf end -- cgit v1.2.3 From eea42e06af745f0a7ae68d0d364a8f71d72823fe Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 1 Aug 2019 13:13:32 +0900 Subject: Add new specifiers/modifiers to format string of `mrb_vfromat()` Format sequence syntax: %[modifier]specifier Modifiers: ----------+------------------------------------------------------------ Modifier | Meaning ----------+------------------------------------------------------------ ! | Convert to string by corresponding `inspect` instead of | corresponding `to_s`. ----------+------------------------------------------------------------ Specifiers: ----------+----------------+-------------------------------------------- Specifier | Argument Type | Note ----------+----------------+-------------------------------------------- c | char | d,i | mrb_int | f | mrb_float | l | char*, mrb_int | Arguments are string and length. n | mrb_sym | s | char* | Argument is NUL terminated string. t | mrb_value | Convert to type (class) of object. v,S | mrb_value | C | struct RClass* | T | mrb_value | Convert to real type (class) of object. Y | mrb_value | Same as `!v` if argument is `true`, `false` | | or `nil`, otherwise same as `T`. % | - | Convert to percent sign itself (no argument | | taken). ----------+----------------+-------------------------------------------- This change will increase the binary size, but replacing all format strings with new specifiers/modifiers will decrease the size because it reduces inline expansion of `mrb_obj_value()`, etc. at the caller. --- mrbgems/mruby-test/driver.c | 3 + mrbgems/mruby-test/mrbgem.rake | 7 +- mrbgems/mruby-test/vformat.c | 186 +++++++++++++++++++++++++++++++++++++++++ src/error.c | 162 ++++++++++++++++++++++++++--------- test/t/vformat.rb | 88 +++++++++++++++++++ 5 files changed, 404 insertions(+), 42 deletions(-) create mode 100644 mrbgems/mruby-test/vformat.c create mode 100644 test/t/vformat.rb (limited to 'test') diff --git a/mrbgems/mruby-test/driver.c b/mrbgems/mruby-test/driver.c index b6c9fab35..a5f723927 100644 --- a/mrbgems/mruby-test/driver.c +++ b/mrbgems/mruby-test/driver.c @@ -21,6 +21,7 @@ extern const uint8_t mrbtest_assert_irep[]; void mrbgemtest_init(mrb_state* mrb); +void mrb_init_test_vformat(mrb_state* mrb); /* Print a short remark for the user */ static void @@ -231,6 +232,8 @@ mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose) #endif #endif + mrb_init_test_vformat(mrb); + if (verbose) { mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); } diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index dcb7bb719..bf90e0791 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -15,8 +15,9 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mrbtest_lib = libfile("#{build_dir}/mrbtest") mrbtest_objs = [] - driver_obj = objfile("#{build_dir}/driver") - # driver = "#{spec.dir}/driver.c" + driver_objs = Dir.glob("#{dir}/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| + objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) + end assert_c = "#{build_dir}/assert.c" assert_rb = "#{MRUBY_ROOT}/test/assert.rb" @@ -133,7 +134,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end unless build.build_mrbtest_lib_only? - file exec => [driver_obj, mlib, mrbtest_lib, build.libmruby_static] do |t| + file exec => [*driver_objs, mlib, mrbtest_lib, build.libmruby_static] do |t| gem_flags = build.gems.map { |g| g.linker.flags } gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c new file mode 100644 index 000000000..a10e49b08 --- /dev/null +++ b/mrbgems/mruby-test/vformat.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include + +#define NATIVE_TYPES \ + char c; \ + mrb_float f; \ + mrb_int i; \ + mrb_sym n; \ + char *s; \ + struct RClass *C + +typedef enum { + ARG_c, + ARG_f, + ARG_i, + ARG_n, + ARG_s, + ARG_C, + ARG_v, +} VFArgumentType; + +typedef struct { + VFArgumentType type; + union { NATIVE_TYPES; }; +} VFNative; + +typedef struct { + VFArgumentType type; + union { + NATIVE_TYPES; + mrb_value v; + }; +} VFArgument; + +static void +native_free(mrb_state *mrb, void *data) +{ + VFNative *native = (VFNative*)data; + if (native->type == ARG_s) mrb_free(mrb, native->s); + mrb_free(mrb, native); +} + +static const struct mrb_data_type native_data_type = { + "TestVFormat::Native", native_free +}; + +static mrb_value +native_initialize(mrb_state *mrb, mrb_value self) +{ + VFNative data, *datap; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + switch (mrb_type(obj)) { + case MRB_TT_FLOAT: + data.f = mrb_float(obj); + data.type = ARG_f; + break; + case MRB_TT_FIXNUM: + data.i = mrb_fixnum(obj); + data.type = ARG_i; + break; + case MRB_TT_SYMBOL: + data.n = mrb_symbol(obj); + data.type = ARG_n; + break; + case MRB_TT_CLASS: case MRB_TT_SCLASS: case MRB_TT_MODULE: + data.C = mrb_class_ptr(obj); + data.type = ARG_C; + break; + case MRB_TT_STRING: { + mrb_int len = RSTRING_LEN(obj); + const char *s = RSTRING_PTR(obj); + if (len == 1) { + /* one byte string is considered char */ + data.c = s[0]; + data.type = ARG_c; + } + else { + data.s = (char*)mrb_malloc(mrb, len + 1); + memcpy(data.s, s, len); + data.s[len] = '\0'; + data.type = ARG_s; + } + break; + } + default: { + mrb_value msg = mrb_str_new_cstr(mrb, "native type for "); + mrb_str_cat_cstr(mrb, msg, mrb_class_name(mrb, mrb_class(mrb, obj))); + mrb_str_cat_cstr(mrb, msg, " is unknown"); + mrb_raise(mrb, E_ARGUMENT_ERROR, RSTRING_PTR(msg)); + } + } + + datap = (VFNative*)mrb_malloc(mrb, sizeof(VFNative)); + *datap = data; + mrb_data_init(self, datap, &native_data_type); + return self; +} + +static VFArgument* +arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, + VFArgument *vf_arg) +{ + if (mrb_obj_is_instance_of(mrb, obj, native_class)) { + const VFNative *native = (VFNative*)DATA_PTR(obj); + *(VFNative*)vf_arg = *native; + } + else { + vf_arg->v = obj; + vf_arg->type = ARG_v; + } + return vf_arg; +} + +#define VF_FORMAT_INIT(klass) \ + struct RClass *vf_native_class = \ + mrb_class_get_under(mrb, mrb_class_ptr(klass), "Native"); \ + VFArgument vf_args[2]; + +#define VF_ARG(args, idx) \ + arg_from_obj(mrb, args[idx], vf_native_class, &vf_args[idx]) + +#define VF_FORMAT0(fmt) mrb_format(mrb, fmt); +#define VF_FORMAT1(fmt, args) \ + (VF_ARG(args, 0), VF_FORMAT_TYPED(fmt, 1, vf_args, NULL)) +#define VF_FORMAT2(fmt, args) ( \ + VF_ARG(args, 0), VF_ARG(args, 1), \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, c) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, s) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, C) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, v) : \ + mrb_nil_value() /* not reached */ \ +) +#define VF_FORMAT2_COND_EXPR(fmt, a1, a2, t) \ + a1->type == ARG_##t ? VF_FORMAT_TYPED(fmt, 2, a2, (a1)->t) +#define VF_FORMAT_TYPED(fmt, n_arg, type_a, v1) \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, c) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, s) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, C) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, v) : \ + mrb_nil_value() /* not reached */ +#define VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, t) \ + (type_a)->type == ARG_##t ? n_arg == 1 ? \ + mrb_format(mrb, fmt, (type_a)->t) : mrb_format(mrb, fmt, v1, (type_a)->t) + +static mrb_value +vf_s_format(mrb_state *mrb, mrb_value klass) +{ + mrb_value fmt_str, args[2]; + mrb_int argc = mrb_get_args(mrb, "S|oo", &fmt_str, args, args+1); + const char *fmt = mrb_string_value_cstr(mrb, &fmt_str); + + VF_FORMAT_INIT(klass); + + switch (argc) { + case 1: return VF_FORMAT0(fmt); + case 2: return VF_FORMAT1(fmt, args); + case 3: return VF_FORMAT2(fmt, args); + default: return mrb_nil_value(); /* not reached */ + } +} + +void +mrb_init_test_vformat(mrb_state *mrb) +{ + struct RClass *vf, *n; + + vf = mrb_define_module(mrb, "TestVFormat"); + mrb_define_class_method(mrb, vf, "format", vf_s_format, MRB_ARGS_ARG(1,2)); + + n = mrb_define_class_under(mrb, vf, "Native", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_DATA); + mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(1)); + mrb_singleton_class(mrb, mrb_obj_value(n)); + mrb_define_alias(mrb, n->c, "[]", "new"); +} diff --git a/src/error.c b/src/error.c index 4c1b67c99..d8224622b 100644 --- a/src/error.c +++ b/src/error.c @@ -260,59 +260,143 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg))); } +/* + * vsprintf like formatting. + * + * The syntax of a format sequence is as follows. + * + * %[modifier]specifier + * + * The modifiers are: + * + * ----------+------------------------------------------------------------ + * Modifier | Meaning + * ----------+------------------------------------------------------------ + * ! | Convert to string by corresponding `inspect` instead of + * | corresponding `to_s`. + * ----------+------------------------------------------------------------ + * + * The specifiers are: + * + * ----------+----------------+-------------------------------------------- + * Specifier | Argument Type | Note + * ----------+----------------+-------------------------------------------- + * c | char | + * d,i | mrb_int | + * f | mrb_float | + * l | char*, mrb_int | Arguments are string and length. + * n | mrb_sym | + * s | char* | Argument is NUL terminated string. + * t | mrb_value | Convert to type (class) of object. + * v,S | mrb_value | + * C | struct RClass* | + * T | mrb_value | Convert to real type (class) of object. + * Y | mrb_value | Same as `!v` if argument is `true`, `false` + * | | or `nil`, otherwise same as `T`. + * % | - | Convert to percent sign itself (no argument + * | | taken). + * ----------+----------------+-------------------------------------------- + */ MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { - const char *p = format; - const char *b = p; - ptrdiff_t size; - int ai0 = mrb_gc_arena_save(mrb); - mrb_value ary = mrb_ary_new_capa(mrb, 4); + const char *chars, *p = format, *b = format, *e; + char ch; + struct RClass *cls; + mrb_int len; + mrb_bool inspect = FALSE; + mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); while (*p) { const char c = *p++; - + e = p; if (c == '%') { - if (*p == 'S') { - mrb_value val; - - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - val = va_arg(ap, mrb_value); - mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val)); - b = p + 1; + if (*p == '!') { + inspect = TRUE; + ++p; } - } - else if (c == '\\') { - if (*p) { - size = p - b - 1; - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); - mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1)); - b = ++p; - } - else { - break; + if (!*p) break; + switch (*p) { + case 'c': + ch = (char)va_arg(ap, int); + chars = &ch; + len = 1; + goto L_cat; + case 'd': case 'i': + obj = mrb_fixnum_value(va_arg(ap, mrb_int)); + goto L_cat_obj; + case 'f': + obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); + goto L_cat_obj; + case 'l': + chars = va_arg(ap, char*); + len = va_arg(ap, mrb_int); + L_cat: + if (inspect) { + obj = mrb_str_new(mrb, chars, len); + goto L_cat_obj; + } + mrb_str_cat(mrb, result, b, e - b - 1); + mrb_str_cat(mrb, result, chars, len); + b = ++p; + mrb_gc_arena_restore(mrb, ai); + break; + case 'n': + obj = mrb_symbol_value(va_arg(ap, mrb_sym)); + goto L_cat_obj; + case 's': + chars = va_arg(ap, char*); + len = strlen(chars); + goto L_cat; + case 't': + cls = mrb_class(mrb, va_arg(ap, mrb_value)); + goto L_cat_class; + case 'v': case 'S': + obj = va_arg(ap, mrb_value); + L_cat_obj: + str = (inspect ? mrb_inspect : mrb_obj_as_string)(mrb, obj); + chars = RSTRING_PTR(str); + len = RSTRING_LEN(str); + inspect = FALSE; + goto L_cat; + case 'C': + cls = va_arg(ap, struct RClass*); + L_cat_class: + obj = mrb_obj_value(cls); + goto L_cat_obj; + case 'T': + obj = va_arg(ap, mrb_value); + L_cat_real_class_of: + cls = mrb_obj_class(mrb, obj); + goto L_cat_class; + case 'Y': + obj = va_arg(ap, mrb_value); + if (!mrb_test(obj) || mrb_true_p(obj)) { + inspect = TRUE; + goto L_cat_obj; + } + else { + goto L_cat_real_class_of; + } + case '%': + L_cat_current: + chars = p; + len = 1; + goto L_cat; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p); } } - mrb_gc_arena_restore(mrb, ai); - } - if (b == format) { - mrb_gc_arena_restore(mrb, ai0); - return mrb_str_new_cstr(mrb, format); - } - else { - mrb_value val; + else if (c == '\\') { + if (!*p) break; + goto L_cat_current; - size = p - b; - if (size > 0) { - mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); } - val = mrb_ary_join(mrb, ary, mrb_nil_value()); - mrb_gc_arena_restore(mrb, ai0); - mrb_gc_protect(mrb, val); - return val; } + + mrb_str_cat(mrb, result, b, p - b); + return result; } MRB_API mrb_value diff --git a/test/t/vformat.rb b/test/t/vformat.rb new file mode 100644 index 000000000..2270d6490 --- /dev/null +++ b/test/t/vformat.rb @@ -0,0 +1,88 @@ +def assert_format(exp, args) + assert_equal(exp, TestVFormat.format(*args)) +end + +def assert_format_pattern(exp_pattern, args) + assert_match(exp_pattern, TestVFormat.format(*args)) +end + +# Pass if ArgumentError is raised or return value is +exp+. +def assert_implementation_dependent(exp, args) + begin + ret = TestVFormat.format(*args) + rescue ArgumentError + return pass + end + if ret == exp + pass + else + flunk "", "Expected ArgumentError is raised or #{ret.inspect} to be #{exp}." + end +end + +def sclass(v) + class << v + self + end +end + +assert('mrb_vformat') do + n = TestVFormat::Native + assert_format '', [''] + assert_format 'No specifier!', ['No specifier!'] + assert_format '`c`: C', ['`c`: %c', n[?C]] + assert_format '`d`: 123', ['`d`: %d', n[123]] + assert_format '`i`: -83', ['`i`: %i', n[-83]] + assert_format '`f`: 0.0125', ['`f`: %f', n[0.0125]] + assert_format '`t`: NilClass', ['`t`: %t', nil] + assert_format '`t`: FalseClass', ['`t`: %t', false] + assert_format '`t`: TrueClass', ['`t`: %t', true] + assert_format '`t`: Fixnum', ['`t`: %t', 0] + assert_format '`t`: Hash', ['`t`: %t', k: "value"] + assert_format_pattern '#>>', ['%t', sclass({})] + assert_format '-Infinity', ['%f', n[-Float::INFINITY]] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n[Float::NAN]] + assert_format 'string and length', ['string %l length', n['andante'], n[3]] + assert_format '`n`: sym', ['`n`: %n', n[:sym]] + assert_format '%C文字列%', ['%s', n['%C文字列%']] + assert_format '`C`: Kernel module', ['`C`: %C module', n[Kernel]] + assert_format '`C`: NilClass', ['`C`: %C', n[nil.class]] + assert_format_pattern '#>', ['%C', n[sclass("")]] + assert_format '`T`: NilClass', ['`T`: %T', nil] + assert_format '`T`: FalseClass', ['`T`: %T', false] + assert_format '`T`: TrueClass', ['`T`: %T', true] + assert_format '`T`: Fixnum', ['`T`: %T', 0] + assert_format '`T`: Hash', ['`T`: %T', k: "value"] + assert_format_pattern 'Class', ['%T', sclass({})] + assert_format '`Y`: nil', ['`Y`: %Y', nil] + assert_format '`Y`: false', ['`Y`: %Y', false] + assert_format '`Y`: true', ['`Y`: %Y', true] + assert_format '`Y`: Fixnum', ['`Y`: %Y', 0] + assert_format '`Y`: Hash', ['`Y`: %Y', k: "value"] + assert_format 'Class', ['%Y', sclass({})] + assert_format_pattern '#>', ['%v', sclass("")] + assert_format '`v`: 1...3', ['`v`: %v', 1...3] + assert_format '`S`: {:a=>1, "b"=>"c"}', ['`S`: %S', a: 1, "b" => ?c] + assert_format 'percent: %', ['percent: %%'] + assert_format '"I": inspect char', ['%!c: inspect char', n[?I]] + assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n[709]] + assert_format '"a\x00b\xff"', ['%!l', n["a\000b\xFFc\000d"], n[4]] + assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n['&.'.to_sym]] + assert_format 'inspect "String"', ['inspect %!v', 'String'] + assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] + assert_format_pattern '`!C`: #', ['`!C`: %!C', n[Class.new]] + assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n[:ab], 'cd'] + assert_format 'to_s -> inspect: x:y', ['to_s -> inspect: %v%!v', 'x', :y] + assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n[:b]] + assert_format 'Y -> to_s: nile', ['Y -> to_s: %Y%v', nil, "e"] + assert_format '"abc":Z', ['%!s%!n', n['abc'], n[:Z]] + assert_format 'escape: \\%a,b,c,d', ['escape: \\\\\%a,b,\c%v', ',d'] + + assert_implementation_dependent 'unknown specifier: %^', + ['unknown specifier: %^'] + assert_implementation_dependent 'unknown specifier with modifier: %!^', + ['unknown specifier with modifier: %!^'] + assert_implementation_dependent 'termination is \\', ['termination is \\'] + assert_implementation_dependent 'termination is %', ['termination is %'] + assert_implementation_dependent 'termination is %!', ['termination is %!'] +end -- cgit v1.2.3 From d1817e77910a2747d2bc602964a5f51a1490a252 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 2 Aug 2019 17:15:34 +0900 Subject: Change the `mrb_vformat` specifier `%d` for `int` It potentially breaks, for example, in the case of `mrb_int` is 64-bit and more smaller type is passed by `%d`. In fact, the problem could become apparent when I used `%d` to `backtrace_location::lineno` in `src/backtrace.c:mrb_unpack_backtrace()` on AppVeyor. Therefore, change `%d` for `int` (not `mrb_int`) so that it can be used mostly without casting. --- mrbgems/mruby-test/vformat.c | 90 ++++++++++++++++++++++---------------------- src/error.c | 8 ++-- test/t/vformat.rb | 42 +++++++++++---------- 3 files changed, 73 insertions(+), 67 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index a10e49b08..e6581d6be 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -6,14 +6,28 @@ #define NATIVE_TYPES \ char c; \ + int d; \ mrb_float f; \ mrb_int i; \ mrb_sym n; \ char *s; \ struct RClass *C +#define NATIVE_DEFINE_TYPE_FUNC(t) \ + static mrb_value \ + native_s_##t(mrb_state *mrb, mrb_value klass) \ + { \ + mrb_value obj, type = mrb_fixnum_value(ARG_##t); \ + mrb_get_args(mrb, "o", &obj); \ + return mrb_funcall(mrb, klass, "new", 2, type, obj); \ + } + +#define NATIVE_DEFINE_TYPE_METHOD(t) \ + mrb_define_class_method(mrb, n, #t, native_s_##t, MRB_ARGS_REQ(1)) + typedef enum { ARG_c, + ARG_d, ARG_f, ARG_i, ARG_n, @@ -51,56 +65,37 @@ static mrb_value native_initialize(mrb_state *mrb, mrb_value self) { VFNative data, *datap; + mrb_int type; mrb_value obj; - mrb_get_args(mrb, "o", &obj); - switch (mrb_type(obj)) { - case MRB_TT_FLOAT: - data.f = mrb_float(obj); - data.type = ARG_f; - break; - case MRB_TT_FIXNUM: - data.i = mrb_fixnum(obj); - data.type = ARG_i; - break; - case MRB_TT_SYMBOL: - data.n = mrb_symbol(obj); - data.type = ARG_n; - break; - case MRB_TT_CLASS: case MRB_TT_SCLASS: case MRB_TT_MODULE: - data.C = mrb_class_ptr(obj); - data.type = ARG_C; - break; - case MRB_TT_STRING: { - mrb_int len = RSTRING_LEN(obj); - const char *s = RSTRING_PTR(obj); - if (len == 1) { - /* one byte string is considered char */ - data.c = s[0]; - data.type = ARG_c; - } - else { - data.s = (char*)mrb_malloc(mrb, len + 1); - memcpy(data.s, s, len); - data.s[len] = '\0'; - data.type = ARG_s; - } - break; - } - default: { - mrb_value msg = mrb_str_new_cstr(mrb, "native type for "); - mrb_str_cat_cstr(mrb, msg, mrb_class_name(mrb, mrb_class(mrb, obj))); - mrb_str_cat_cstr(mrb, msg, " is unknown"); - mrb_raise(mrb, E_ARGUMENT_ERROR, RSTRING_PTR(msg)); - } + mrb_get_args(mrb, "io", &type, &obj); + data.type = (VFArgumentType)type; + switch (data.type) { + case ARG_c: data.c = RSTRING_PTR(obj)[0]; break; + case ARG_d: data.d = (int)mrb_fixnum(obj); break; + case ARG_f: data.f = mrb_float(obj); break; + case ARG_i: data.i = mrb_fixnum(obj); break; + case ARG_n: data.n = mrb_symbol(obj); break; + case ARG_s: data.s = (char*)mrb_malloc(mrb, RSTRING_LEN(obj) + 1); + memcpy(data.s, RSTRING_PTR(obj), RSTRING_LEN(obj)); + data.s[RSTRING_LEN(obj)] = '\0'; break; + case ARG_C: data.C = mrb_class_ptr(obj); break; + default: mrb_raise(mrb, E_ARGUMENT_ERROR, "unknown type"); } - datap = (VFNative*)mrb_malloc(mrb, sizeof(VFNative)); *datap = data; mrb_data_init(self, datap, &native_data_type); return self; } +NATIVE_DEFINE_TYPE_FUNC(c) +NATIVE_DEFINE_TYPE_FUNC(d) +NATIVE_DEFINE_TYPE_FUNC(f) +NATIVE_DEFINE_TYPE_FUNC(i) +NATIVE_DEFINE_TYPE_FUNC(n) +NATIVE_DEFINE_TYPE_FUNC(s) +NATIVE_DEFINE_TYPE_FUNC(C) + static VFArgument* arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VFArgument *vf_arg) @@ -130,6 +125,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, #define VF_FORMAT2(fmt, args) ( \ VF_ARG(args, 0), VF_ARG(args, 1), \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, c) : \ + VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, d) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ @@ -142,6 +138,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, a1->type == ARG_##t ? VF_FORMAT_TYPED(fmt, 2, a2, (a1)->t) #define VF_FORMAT_TYPED(fmt, n_arg, type_a, v1) \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, c) : \ + VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, d) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ @@ -180,7 +177,12 @@ mrb_init_test_vformat(mrb_state *mrb) n = mrb_define_class_under(mrb, vf, "Native", mrb->object_class); MRB_SET_INSTANCE_TT(n, MRB_TT_DATA); - mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(1)); - mrb_singleton_class(mrb, mrb_obj_value(n)); - mrb_define_alias(mrb, n->c, "[]", "new"); + NATIVE_DEFINE_TYPE_METHOD(c); + NATIVE_DEFINE_TYPE_METHOD(d); + NATIVE_DEFINE_TYPE_METHOD(f); + NATIVE_DEFINE_TYPE_METHOD(i); + NATIVE_DEFINE_TYPE_METHOD(n); + NATIVE_DEFINE_TYPE_METHOD(s); + NATIVE_DEFINE_TYPE_METHOD(C); + mrb_define_method(mrb, n, "initialize", native_initialize, MRB_ARGS_REQ(2)); } diff --git a/src/error.c b/src/error.c index d8224622b..6e7c3763a 100644 --- a/src/error.c +++ b/src/error.c @@ -282,8 +282,9 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) * Specifier | Argument Type | Note * ----------+----------------+-------------------------------------------- * c | char | - * d,i | mrb_int | + * d | int | * f | mrb_float | + * i | mrb_int | * l | char*, mrb_int | Arguments are string and length. * n | mrb_sym | * s | char* | Argument is NUL terminated string. @@ -303,7 +304,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) const char *chars, *p = format, *b = format, *e; char ch; struct RClass *cls; - mrb_int len; + mrb_int len, i; mrb_bool inspect = FALSE; mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); @@ -324,7 +325,8 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) len = 1; goto L_cat; case 'd': case 'i': - obj = mrb_fixnum_value(va_arg(ap, mrb_int)); + i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); + obj = mrb_fixnum_value(i); goto L_cat_obj; case 'f': obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); diff --git a/test/t/vformat.rb b/test/t/vformat.rb index 2270d6490..d124e92b2 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -30,24 +30,26 @@ assert('mrb_vformat') do n = TestVFormat::Native assert_format '', [''] assert_format 'No specifier!', ['No specifier!'] - assert_format '`c`: C', ['`c`: %c', n[?C]] - assert_format '`d`: 123', ['`d`: %d', n[123]] - assert_format '`i`: -83', ['`i`: %i', n[-83]] - assert_format '`f`: 0.0125', ['`f`: %f', n[0.0125]] + assert_format '`c`: C', ['`c`: %c', n.c(?C)] + assert_format '`d`: 123', ['`d`: %d', n.d(123)] + assert_format '`d`: -79', ['`d`: %d', n.d(-79)] + assert_format '`i`: 514', ['`i`: %i', n.i(514)] + assert_format '`i`: -83', ['`i`: %i', n.i(-83)] + assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] assert_format '`t`: NilClass', ['`t`: %t', nil] assert_format '`t`: FalseClass', ['`t`: %t', false] assert_format '`t`: TrueClass', ['`t`: %t', true] assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format '-Infinity', ['%f', n[-Float::INFINITY]] - assert_format 'NaN: Not a Number', ['%f: Not a Number', n[Float::NAN]] - assert_format 'string and length', ['string %l length', n['andante'], n[3]] - assert_format '`n`: sym', ['`n`: %n', n[:sym]] - assert_format '%C文字列%', ['%s', n['%C文字列%']] - assert_format '`C`: Kernel module', ['`C`: %C module', n[Kernel]] - assert_format '`C`: NilClass', ['`C`: %C', n[nil.class]] - assert_format_pattern '#>', ['%C', n[sclass("")]] + assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] + assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] + assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] + assert_format '%C文字列%', ['%s', n.s('%C文字列%')] + assert_format '`C`: Kernel module', ['`C`: %C module', n.C(Kernel)] + assert_format '`C`: NilClass', ['`C`: %C', n.C(nil.class)] + assert_format_pattern '#>', ['%C', n.C(sclass(""))] assert_format '`T`: NilClass', ['`T`: %T', nil] assert_format '`T`: FalseClass', ['`T`: %T', false] assert_format '`T`: TrueClass', ['`T`: %T', true] @@ -64,18 +66,18 @@ assert('mrb_vformat') do assert_format '`v`: 1...3', ['`v`: %v', 1...3] assert_format '`S`: {:a=>1, "b"=>"c"}', ['`S`: %S', a: 1, "b" => ?c] assert_format 'percent: %', ['percent: %%'] - assert_format '"I": inspect char', ['%!c: inspect char', n[?I]] - assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n[709]] - assert_format '"a\x00b\xff"', ['%!l', n["a\000b\xFFc\000d"], n[4]] - assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n['&.'.to_sym]] + assert_format '"I": inspect char', ['%!c: inspect char', n.c(?I)] + assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n.i(709)] + assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.i(4)] + assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n.n(:'&.')] assert_format 'inspect "String"', ['inspect %!v', 'String'] assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] - assert_format_pattern '`!C`: #', ['`!C`: %!C', n[Class.new]] - assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n[:ab], 'cd'] + assert_format_pattern '`!C`: #', ['`!C`: %!C', n.C(Class.new)] + assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n.n(:ab), 'cd'] assert_format 'to_s -> inspect: x:y', ['to_s -> inspect: %v%!v', 'x', :y] - assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n[:b]] + assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n.n(:b)] assert_format 'Y -> to_s: nile', ['Y -> to_s: %Y%v', nil, "e"] - assert_format '"abc":Z', ['%!s%!n', n['abc'], n[:Z]] + assert_format '"abc":Z', ['%!s%!n', n.s('abc'), n.n('Z'.to_sym)] assert_format 'escape: \\%a,b,c,d', ['escape: \\\\\%a,b,\c%v', ',d'] assert_implementation_dependent 'unknown specifier: %^', -- cgit v1.2.3 From a4243360a2f8248dbf23b46ca14a7a59c0479b32 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 3 Aug 2019 11:54:45 +0900 Subject: Fix `mrb_vformat("%f")` with `MRB_USE_FLOAT` It potentially not work when `mrb_float` is `float` because `float` variable in variable length arguments is promoted to `double`. Also I fixed build with `MRB_WITHOUT_FLOAT`. --- mrbgems/mruby-test/vformat.c | 5 +++++ src/error.c | 4 +++- test/t/vformat.rb | 8 +++++--- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index e6581d6be..e02383f77 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -4,6 +4,11 @@ #include #include +#ifdef MRB_WITHOUT_FLOAT +typedef mrb_int mrb_float; +#define mrb_float(o) mrb_fixnum(o) +#endif + #define NATIVE_TYPES \ char c; \ int d; \ diff --git a/src/error.c b/src/error.c index 6e7c3763a..3ee137c95 100644 --- a/src/error.c +++ b/src/error.c @@ -328,9 +328,11 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) i = *p == 'd' ? (mrb_int)va_arg(ap, int) : va_arg(ap, mrb_int); obj = mrb_fixnum_value(i); goto L_cat_obj; +#ifndef MRB_WITHOUT_FLOAT case 'f': - obj = mrb_float_value(mrb, va_arg(ap, mrb_float)); + obj = mrb_float_value(mrb, (mrb_float)va_arg(ap, double)); goto L_cat_obj; +#endif case 'l': chars = va_arg(ap, char*); len = va_arg(ap, mrb_int); diff --git a/test/t/vformat.rb b/test/t/vformat.rb index d124e92b2..e99616064 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -35,15 +35,12 @@ assert('mrb_vformat') do assert_format '`d`: -79', ['`d`: %d', n.d(-79)] assert_format '`i`: 514', ['`i`: %i', n.i(514)] assert_format '`i`: -83', ['`i`: %i', n.i(-83)] - assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] assert_format '`t`: NilClass', ['`t`: %t', nil] assert_format '`t`: FalseClass', ['`t`: %t', false] assert_format '`t`: TrueClass', ['`t`: %t', true] assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] - assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] assert_format '%C文字列%', ['%s', n.s('%C文字列%')] @@ -87,4 +84,9 @@ assert('mrb_vformat') do assert_implementation_dependent 'termination is \\', ['termination is \\'] assert_implementation_dependent 'termination is %', ['termination is %'] assert_implementation_dependent 'termination is %!', ['termination is %!'] + + skip unless Object.const_defined?(:Float) + assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)] + assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)] + assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)] end -- cgit v1.2.3 From 1e9cb74cc6dd2fbe1b68edf3b73c7acfe7fc7831 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 3 Aug 2019 17:46:11 +0900 Subject: Change second argument to `%l` of `mrb_vformat()` to `size_t` from `mrb_int` - `size_t` is more commonly used. - `len` argument of `mrb_str_new()` is `size_t`. NOTE: The test for `%l` is temporarily disabled because adding a new type to `mrbgems/mruby-test/vformat.c` causes an error (memory error?) on Visual Studio 2017 in AppVeyor. --- mrbgems/mruby-test/vformat.c | 7 +++++++ src/error.c | 7 ++++--- tasks/toolchains/visualcpp.rake | 2 +- test/t/vformat.rb | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-test/vformat.c b/mrbgems/mruby-test/vformat.c index e02383f77..6e0c2887f 100644 --- a/mrbgems/mruby-test/vformat.c +++ b/mrbgems/mruby-test/vformat.c @@ -14,6 +14,7 @@ typedef mrb_int mrb_float; int d; \ mrb_float f; \ mrb_int i; \ +/* size_t l; */\ mrb_sym n; \ char *s; \ struct RClass *C @@ -35,6 +36,7 @@ typedef enum { ARG_d, ARG_f, ARG_i, +/* ARG_l,*/ ARG_n, ARG_s, ARG_C, @@ -80,6 +82,7 @@ native_initialize(mrb_state *mrb, mrb_value self) case ARG_d: data.d = (int)mrb_fixnum(obj); break; case ARG_f: data.f = mrb_float(obj); break; case ARG_i: data.i = mrb_fixnum(obj); break; +/* case ARG_l: data.l = (size_t)mrb_fixnum(obj); break;*/ case ARG_n: data.n = mrb_symbol(obj); break; case ARG_s: data.s = (char*)mrb_malloc(mrb, RSTRING_LEN(obj) + 1); memcpy(data.s, RSTRING_PTR(obj), RSTRING_LEN(obj)); @@ -97,6 +100,7 @@ NATIVE_DEFINE_TYPE_FUNC(c) NATIVE_DEFINE_TYPE_FUNC(d) NATIVE_DEFINE_TYPE_FUNC(f) NATIVE_DEFINE_TYPE_FUNC(i) +/*NATIVE_DEFINE_TYPE_FUNC(l)*/ NATIVE_DEFINE_TYPE_FUNC(n) NATIVE_DEFINE_TYPE_FUNC(s) NATIVE_DEFINE_TYPE_FUNC(C) @@ -133,6 +137,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, d) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, f) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, i) : \ +/* VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, l) : */\ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, n) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, s) : \ VF_FORMAT2_COND_EXPR(fmt, vf_args, vf_args+1, C) : \ @@ -146,6 +151,7 @@ arg_from_obj(mrb_state *mrb, mrb_value obj, struct RClass *native_class, VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, d) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, f) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, i) : \ +/* VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, l) : */\ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, n) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, s) : \ VF_FORMAT_TYPED_COND_EXPR(fmt, n_arg, type_a, v1, C) : \ @@ -186,6 +192,7 @@ mrb_init_test_vformat(mrb_state *mrb) NATIVE_DEFINE_TYPE_METHOD(d); NATIVE_DEFINE_TYPE_METHOD(f); NATIVE_DEFINE_TYPE_METHOD(i); +/* NATIVE_DEFINE_TYPE_METHOD(l);*/ NATIVE_DEFINE_TYPE_METHOD(n); NATIVE_DEFINE_TYPE_METHOD(s); NATIVE_DEFINE_TYPE_METHOD(C); diff --git a/src/error.c b/src/error.c index 3ee137c95..0ca7f5917 100644 --- a/src/error.c +++ b/src/error.c @@ -285,7 +285,7 @@ mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) * d | int | * f | mrb_float | * i | mrb_int | - * l | char*, mrb_int | Arguments are string and length. + * l | char*, size_t | Arguments are string and length. * n | mrb_sym | * s | char* | Argument is NUL terminated string. * t | mrb_value | Convert to type (class) of object. @@ -303,8 +303,9 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) { const char *chars, *p = format, *b = format, *e; char ch; + size_t len; + mrb_int i; struct RClass *cls; - mrb_int len, i; mrb_bool inspect = FALSE; mrb_value result = mrb_str_new_capa(mrb, 128), obj, str; int ai = mrb_gc_arena_save(mrb); @@ -335,7 +336,7 @@ mrb_vformat(mrb_state *mrb, const char *format, va_list ap) #endif case 'l': chars = va_arg(ap, char*); - len = va_arg(ap, mrb_int); + len = va_arg(ap, size_t); L_cat: if (inspect) { obj = mrb_str_new(mrb, chars, len); diff --git a/tasks/toolchains/visualcpp.rake b/tasks/toolchains/visualcpp.rake index 6275059bb..9bf0f085e 100644 --- a/tasks/toolchains/visualcpp.rake +++ b/tasks/toolchains/visualcpp.rake @@ -2,7 +2,7 @@ MRuby::Toolchain.new(:visualcpp) do |conf, _params| conf.cc do |cc| cc.command = ENV['CC'] || 'cl.exe' # C4013: implicit function declaration - cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] + cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /we4013 /Zi /Zm2000 /MD /O2 /D_CRT_SECURE_NO_WARNINGS)] cc.defines = %w(MRB_STACK_EXTEND_DOUBLING) cc.option_include_path = '/I%s' cc.option_define = '/D%s' diff --git a/test/t/vformat.rb b/test/t/vformat.rb index e99616064..679f30407 100644 --- a/test/t/vformat.rb +++ b/test/t/vformat.rb @@ -41,7 +41,7 @@ assert('mrb_vformat') do assert_format '`t`: Fixnum', ['`t`: %t', 0] assert_format '`t`: Hash', ['`t`: %t', k: "value"] assert_format_pattern '#>>', ['%t', sclass({})] - assert_format 'string and length', ['string %l length', n.s('andante'), n.i(3)] +# assert_format 'string and length', ['string %l length', n.s('andante'), n.l(3)] assert_format '`n`: sym', ['`n`: %n', n.n(:sym)] assert_format '%C文字列%', ['%s', n.s('%C文字列%')] assert_format '`C`: Kernel module', ['`C`: %C module', n.C(Kernel)] @@ -65,7 +65,7 @@ assert('mrb_vformat') do assert_format 'percent: %', ['percent: %%'] assert_format '"I": inspect char', ['%!c: inspect char', n.c(?I)] assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n.i(709)] - assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.i(4)] +# assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.l(4)] assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n.n(:'&.')] assert_format 'inspect "String"', ['inspect %!v', 'String'] assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]] -- cgit v1.2.3 From cf5f290fa0b062c8cb99e2aa85f2486f6601f116 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 10 Aug 2019 22:17:35 +0900 Subject: Fix `String#rindex` test for UTF-8 string --- test/t/string.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index 46cbe6e2a..1aa254cd0 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -557,10 +557,9 @@ end assert('String#rindex(UTF-8)', '15.2.10.5.31') do str = "こんにちは世界!\nこんにちは世界!" - assert_nil str.index('さ') - assert_equal 3, str.index('ち') - assert_equal 12, str.index('ち', 10) - assert_equal nil, str.index("さ") + assert_nil str.rindex('さ') + assert_equal 12, str.rindex('ち') + assert_equal 3, str.rindex('ち', 10) end if UTF8STRING # assert('String#scan', '15.2.10.5.32') do -- cgit v1.2.3 From 414ab682f37118288864f5298ea5eb2cd3791dd2 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 10 Aug 2019 22:18:23 +0900 Subject: Add `String#rindex` test for invalid UTF-8 string --- test/t/string.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/t/string.rb b/test/t/string.rb index 1aa254cd0..7e3c327b1 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -560,6 +560,13 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_nil str.rindex('さ') assert_equal 12, str.rindex('ち') assert_equal 3, str.rindex('ち', 10) + + broken = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃" + assert_nil broken.rindex("\x81") # "\x81" is a part of "☁" ("\xe2\x98\x81") + assert_equal 11, broken.rindex("☁") + assert_equal 11, broken.rindex("☁", 12) + assert_equal 11, broken.rindex("☁", 11) + assert_equal 3, broken.rindex("☁", 10) end if UTF8STRING # assert('String#scan', '15.2.10.5.32') do -- cgit v1.2.3 From 6c4278144aa508f7756dd06712e5d8214e2b0a1b Mon Sep 17 00:00:00 2001 From: takumakume Date: Thu, 5 Sep 2019 19:51:54 +0900 Subject: add assert_not_nil method --- test/assert.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test') diff --git a/test/assert.rb b/test/assert.rb index 32dd4ddc6..9b04f5b48 100644 --- a/test/assert.rb +++ b/test/assert.rb @@ -208,6 +208,13 @@ def assert_nil(obj, msg = nil) assert_true(ret, msg, diff) end +def assert_not_nil(obj, msg = nil) + if ret = obj.nil? + diff = " Expected #{obj.inspect} to not be nil." + end + assert_false(ret, msg, diff) +end + def assert_include(*args); _assert_include(true, *args) end def assert_not_include(*args); _assert_include(false, *args) end def _assert_include(affirmed, collection, obj, msg = nil) -- cgit v1.2.3 From 9d08025b8b0fc9828120d48c61bde9c4ba49ce74 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 7 Sep 2019 22:25:08 +0900 Subject: Revert part of #4225 Since in mruby, Integer and Float interchange frequently (mostly on overflow), so adding explicit `.0` can cause problems sometimes. For example: https://github.com/mattn/mruby-json/pull/40 https://github.com/pepabo/mruby-msd/pull/13 https://github.com/mattn/mruby-json/pull/42 --- src/numeric.c | 3 --- test/t/float.rb | 14 +++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/src/numeric.c b/src/numeric.c index 18b8ff461..638f75fd8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -246,9 +246,6 @@ flo_to_s(mrb_state *mrb, mrb_value flt) str = mrb_float_to_str(mrb, flt, fmt); goto insert_dot_zero; } - else { - mrb_str_cat(mrb, str, ".0", 2); - } return str; } diff --git a/test/t/float.rb b/test/t/float.rb index 63bf83f40..dc989636f 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -212,10 +212,10 @@ assert('Float#to_s') do assert_equal("Infinity", Float::INFINITY.to_s) assert_equal("-Infinity", (-Float::INFINITY).to_s) assert_equal("NaN", Float::NAN.to_s) - assert_equal("0.0", 0.0.to_s) - assert_equal("-0.0", -0.0.to_s) + assert_equal("0", 0.0.to_s) + assert_equal("-0", -0.0.to_s) assert_equal("-3.25", -3.25.to_s) - assert_equal("50.0", 50.0.to_s) + assert_equal("50", 50.0.to_s) assert_equal("0.0125", 0.0125.to_s) assert_equal("-0.0125", -0.0125.to_s) assert_equal("1.0e-10", 0.0000000001.to_s) @@ -224,8 +224,8 @@ assert('Float#to_s') do assert_equal("-1.0e+20", -1e20.to_s) assert_equal("1.0e+16", 10000000000000000.0.to_s) assert_equal("-1.0e+16", -10000000000000000.0.to_s) - assert_equal("100000.0", 100000.0.to_s) - assert_equal("-100000.0", -100000.0.to_s) + assert_equal("100000", 100000.0.to_s) + assert_equal("-100000", -100000.0.to_s) if uses_float assert_equal("1.0e+08", 100000000.0.to_s) assert_equal("-1.0e+08", -100000000.0.to_s) @@ -234,8 +234,8 @@ assert('Float#to_s') do else assert_equal("1.0e+15", 1000000000000000.0.to_s) assert_equal("-1.0e+15", -1000000000000000.0.to_s) - assert_equal("100000000000000.0", 100000000000000.0.to_s) - assert_equal("-100000000000000.0", -100000000000000.0.to_s) + assert_equal("100000000000000", 100000000000000.0.to_s) + assert_equal("-100000000000000", -100000000000000.0.to_s) end end -- cgit v1.2.3 From 04b098d000c129b1efde98904b9a1b411b32a46a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Sep 2019 18:49:08 +0900 Subject: Move tests related to `getbyte`, `setbyte`, byteslice` to core. --- mrbgems/mruby-string-ext/test/string.rb | 79 --------------------------------- test/t/string.rb | 79 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 79 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index edbeb02d7..6914fe31d 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -10,85 +10,6 @@ def assert_upto(exp, receiver, *args) assert_equal exp, act end -assert('String#getbyte') do - str1 = "hello" - bytes1 = [104, 101, 108, 108, 111] - assert_equal bytes1[0], str1.getbyte(0) - assert_equal bytes1[-1], str1.getbyte(-1) - assert_equal bytes1[6], str1.getbyte(6) - - str2 = "\xFF" - bytes2 = [0xFF] - assert_equal bytes2[0], str2.getbyte(0) -end - -assert('String#setbyte') do - str1 = "hello" - h = "H".getbyte(0) - str1.setbyte(0, h) - assert_equal(h, str1.getbyte(0)) - assert_equal("Hello", str1) -end - -assert('String#byteslice') do - str1 = "hello" - str2 = "\u3042ab" # "\xE3\x81\x82ab" - - assert_equal("h", str1.byteslice(0)) - assert_equal("e", str1.byteslice(1)) - assert_equal(nil, str1.byteslice(5)) - assert_equal("o", str1.byteslice(-1)) - assert_equal(nil, str1.byteslice(-6)) - assert_equal("\xE3", str2.byteslice(0)) - assert_equal("\x81", str2.byteslice(1)) - assert_equal(nil, str2.byteslice(5)) - assert_equal("b", str2.byteslice(-1)) - assert_equal(nil, str2.byteslice(-6)) - - assert_equal("", str1.byteslice(0, 0)) - assert_equal(str1, str1.byteslice(0, 6)) - assert_equal("el", str1.byteslice(1, 2)) - assert_equal("", str1.byteslice(5, 1)) - assert_equal("o", str1.byteslice(-1, 6)) - assert_equal(nil, str1.byteslice(-6, 1)) - assert_equal(nil, str1.byteslice(0, -1)) - assert_equal("", str2.byteslice(0, 0)) - assert_equal(str2, str2.byteslice(0, 6)) - assert_equal("\x81\x82", str2.byteslice(1, 2)) - assert_equal("", str2.byteslice(5, 1)) - assert_equal("b", str2.byteslice(-1, 6)) - assert_equal(nil, str2.byteslice(-6, 1)) - assert_equal(nil, str2.byteslice(0, -1)) - - assert_equal("ell", str1.byteslice(1..3)) - assert_equal("el", str1.byteslice(1...3)) - assert_equal("h", str1.byteslice(0..0)) - assert_equal("", str1.byteslice(5..0)) - assert_equal("o", str1.byteslice(4..5)) - assert_equal(nil, str1.byteslice(6..0)) - assert_equal("", str1.byteslice(-1..0)) - assert_equal("llo", str1.byteslice(-3..5)) - assert_equal("\x81\x82a", str2.byteslice(1..3)) - assert_equal("\x81\x82", str2.byteslice(1...3)) - assert_equal("\xE3", str2.byteslice(0..0)) - assert_equal("", str2.byteslice(5..0)) - assert_equal("b", str2.byteslice(4..5)) - assert_equal(nil, str2.byteslice(6..0)) - assert_equal("", str2.byteslice(-1..0)) - assert_equal("\x82ab", str2.byteslice(-3..5)) - - assert_raise(ArgumentError) { str1.byteslice } - assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) } - assert_raise(TypeError) { str1.byteslice("1") } - assert_raise(TypeError) { str1.byteslice("1", 2) } - assert_raise(TypeError) { str1.byteslice(1, "2") } - assert_raise(TypeError) { str1.byteslice(1..2, 3) } - - skip unless Object.const_defined?(:Float) - assert_equal("o", str1.byteslice(4.0)) - assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) -end - assert('String#dump') do assert_equal("\"\\x00\"", "\0".dump) assert_equal("\"foo\"", "foo".dump) diff --git a/test/t/string.rb b/test/t/string.rb index 7e3c327b1..c820bfa92 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -784,3 +784,82 @@ assert('String literal concatenation') do assert_equal 3, ('A' "B" 'C').size assert_equal 4, (%(A) "B#{?C}" "D").size end + +assert('String#getbyte') do + str1 = "hello" + bytes1 = [104, 101, 108, 108, 111] + assert_equal bytes1[0], str1.getbyte(0) + assert_equal bytes1[-1], str1.getbyte(-1) + assert_equal bytes1[6], str1.getbyte(6) + + str2 = "\xFF" + bytes2 = [0xFF] + assert_equal bytes2[0], str2.getbyte(0) +end + +assert('String#setbyte') do + str1 = "hello" + h = "H".getbyte(0) + str1.setbyte(0, h) + assert_equal(h, str1.getbyte(0)) + assert_equal("Hello", str1) +end + +assert('String#byteslice') do + str1 = "hello" + str2 = "\u3042ab" # "\xE3\x81\x82ab" + + assert_equal("h", str1.byteslice(0)) + assert_equal("e", str1.byteslice(1)) + assert_equal(nil, str1.byteslice(5)) + assert_equal("o", str1.byteslice(-1)) + assert_equal(nil, str1.byteslice(-6)) + assert_equal("\xE3", str2.byteslice(0)) + assert_equal("\x81", str2.byteslice(1)) + assert_equal(nil, str2.byteslice(5)) + assert_equal("b", str2.byteslice(-1)) + assert_equal(nil, str2.byteslice(-6)) + + assert_equal("", str1.byteslice(0, 0)) + assert_equal(str1, str1.byteslice(0, 6)) + assert_equal("el", str1.byteslice(1, 2)) + assert_equal("", str1.byteslice(5, 1)) + assert_equal("o", str1.byteslice(-1, 6)) + assert_equal(nil, str1.byteslice(-6, 1)) + assert_equal(nil, str1.byteslice(0, -1)) + assert_equal("", str2.byteslice(0, 0)) + assert_equal(str2, str2.byteslice(0, 6)) + assert_equal("\x81\x82", str2.byteslice(1, 2)) + assert_equal("", str2.byteslice(5, 1)) + assert_equal("b", str2.byteslice(-1, 6)) + assert_equal(nil, str2.byteslice(-6, 1)) + assert_equal(nil, str2.byteslice(0, -1)) + + assert_equal("ell", str1.byteslice(1..3)) + assert_equal("el", str1.byteslice(1...3)) + assert_equal("h", str1.byteslice(0..0)) + assert_equal("", str1.byteslice(5..0)) + assert_equal("o", str1.byteslice(4..5)) + assert_equal(nil, str1.byteslice(6..0)) + assert_equal("", str1.byteslice(-1..0)) + assert_equal("llo", str1.byteslice(-3..5)) + assert_equal("\x81\x82a", str2.byteslice(1..3)) + assert_equal("\x81\x82", str2.byteslice(1...3)) + assert_equal("\xE3", str2.byteslice(0..0)) + assert_equal("", str2.byteslice(5..0)) + assert_equal("b", str2.byteslice(4..5)) + assert_equal(nil, str2.byteslice(6..0)) + assert_equal("", str2.byteslice(-1..0)) + assert_equal("\x82ab", str2.byteslice(-3..5)) + + assert_raise(ArgumentError) { str1.byteslice } + assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) } + assert_raise(TypeError) { str1.byteslice("1") } + assert_raise(TypeError) { str1.byteslice("1", 2) } + assert_raise(TypeError) { str1.byteslice(1, "2") } + assert_raise(TypeError) { str1.byteslice(1..2, 3) } + + skip unless Object.const_defined?(:Float) + assert_equal("o", str1.byteslice(4.0)) + assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) +end -- cgit v1.2.3 From 2f7175442fffecc1139312e9e1055ba37ba8527d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 17 Sep 2019 09:28:51 +0900 Subject: Fix `Fixnum#(to_s|inspect)` argument specs Before this patch: $ bin/mruby -e 'p 3.to_s(2)' trace (most recent call last): [0] -e:1 -e:1: 'to_s': wrong number of arguments (1 for 0) (ArgumentError) After this patch: $ bin/mruby -e 'p 3.to_s(2)' "11" --- src/numeric.c | 4 ++-- test/t/integer.rb | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/src/numeric.c b/src/numeric.c index d4ada1809..e6a68f289 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1663,8 +1663,8 @@ mrb_init_numeric(mrb_state *mrb) #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */ #endif - mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */ - mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */ + mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_OPT(1)); mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */ #ifndef MRB_WITHOUT_FLOAT diff --git a/test/t/integer.rb b/test/t/integer.rb index 4ab49eb0a..bd7efa855 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -232,8 +232,16 @@ assert('Integer#to_i', '15.2.8.3.24') do end assert('Integer#to_s', '15.2.8.3.25') do - assert_equal '1', 1.to_s - assert_equal("-1", -1.to_s) + assert_equal "1", 1.to_s + assert_equal "-1", -1.to_s + assert_equal "1010", 10.to_s(2) + assert_equal "a", 10.to_s(36) + assert_equal "-a", -10.to_s(36) + assert_equal "30071", 12345.to_s(8) + assert_raise(ArgumentError) { 10.to_s(-1) } + assert_raise(ArgumentError) { 10.to_s(0) } + assert_raise(ArgumentError) { 10.to_s(1) } + assert_raise(ArgumentError) { 10.to_s(37) } end assert('Integer#truncate', '15.2.8.3.26') do -- cgit v1.2.3 From e61095426bbb0de2ab0a941f9ed3a3acdb7833e8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 19 Sep 2019 20:19:38 +0900 Subject: Simplify arguments check in `String#index` Also fix document about type of the first argument. --- src/string.c | 54 +++++++++++++----------------------------------------- test/t/string.rb | 4 ++++ 2 files changed, 17 insertions(+), 41 deletions(-) (limited to 'test') diff --git a/src/string.c b/src/string.c index 7abb3148c..48df958ec 100644 --- a/src/string.c +++ b/src/string.c @@ -1757,22 +1757,16 @@ mrb_str_include(mrb_state *mrb, mrb_value self) /* * call-seq: * str.index(substring [, offset]) => fixnum or nil - * str.index(fixnum [, offset]) => fixnum or nil - * str.index(regexp [, offset]) => fixnum or nil * * Returns the index of the first occurrence of the given - * substring, - * character (fixnum), or pattern (regexp) in str. - * Returns - * nil if not found. + * substring. Returns nil if not found. * If the second parameter is present, it * specifies the position in the string to begin the search. * - * "hello".index('e') #=> 1 + * "hello".index('l') #=> 2 * "hello".index('lo') #=> 3 * "hello".index('a') #=> nil - * "hello".index(101) #=> 1(101=0x65='e') - * "hello".index(/[aeiou]/, -3) #=> 4 + * "hello".index('l', -2) #=> 3 */ static mrb_value mrb_str_index_m(mrb_state *mrb, mrb_value str) @@ -1780,39 +1774,17 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) mrb_value sub; mrb_int pos; - switch (mrb_get_args(mrb, "|oi", &sub, &pos)) { - case 0: - sub = mrb_nil_value(); - /* fall through */ - case 1: - pos = 0; - break; - case 2: - if (pos < 0) { - mrb_int clen = RSTRING_CHAR_LEN(str); - pos += clen; - if (pos < 0) { - return mrb_nil_value(); - } - } - break; + if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) { + pos = 0; } - - switch (mrb_type(sub)) { - default: { - mrb_value tmp; - - tmp = mrb_check_string_type(mrb, sub); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); - } - sub = tmp; + else if (pos < 0) { + mrb_int clen = RSTRING_CHAR_LEN(str); + pos += clen; + if (pos < 0) { + return mrb_nil_value(); } - /* fall through */ - case MRB_TT_STRING: - pos = str_index_str_by_char(mrb, str, sub, pos); - break; } + pos = str_index_str_by_char(mrb, str, sub, pos); if (pos == -1) return mrb_nil_value(); BYTES_ALIGN_CHECK(pos); @@ -3057,7 +3029,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ - mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ + mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ARG(1,1)); /* 15.2.10.5.22 */ mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */ mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */ @@ -3084,7 +3056,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "getbyte", mrb_str_getbyte, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "setbyte", mrb_str_setbyte, MRB_ARGS_REQ(2)); - mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_method(mrb, s, "byteslice", mrb_str_byteslice, MRB_ARGS_ARG(1,1)); } #ifndef MRB_WITHOUT_FLOAT diff --git a/test/t/string.rb b/test/t/string.rb index c820bfa92..01f3da327 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -451,12 +451,16 @@ assert('String#index', '15.2.10.5.22') do assert_equal 3, 'abcabc'.index('a', 1) assert_equal 5, "hello".index("", 5) assert_equal nil, "hello".index("", 6) + assert_equal 3, "hello".index("l", -2) + assert_raise(ArgumentError) { "hello".index } + assert_raise(TypeError) { "hello".index(101) } end assert('String#index(UTF-8)', '15.2.10.5.22') do assert_equal 0, '⓿➊➋➌➍➎'.index('⓿') assert_nil '⓿➊➋➌➍➎'.index('➓') assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', 1) + assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', -7) assert_equal 6, "⓿➊➋➌➍➎".index("", 6) assert_equal nil, "⓿➊➋➌➍➎".index("", 7) assert_equal 0, '⓿➊➋➌➍➎'.index("\xe2") -- cgit v1.2.3 From 549317a36b239cbe51a75b4cdb4abd49298773e8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 23 Sep 2019 21:59:35 +0900 Subject: Fix `Fixnum` overflow test in `Integer#<<` test - Skip when `MRB_WITHOUT_FLOAT` is defined. - Make `Fixnum` overflow even when `MRB_INT64` is defined. --- test/t/integer.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/t/integer.rb b/test/t/integer.rb index bd7efa855..f9c44a64f 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -154,11 +154,11 @@ assert('Integer#<<', '15.2.8.3.12') do # Left Shift by a negative is Right Shift assert_equal 23, 46 << -1 - # Left Shift by 31 is bitShift overflow to SignedInt - assert_equal 2147483648, 1 << 31 + skip unless Object.const_defined?(:Float) - # -3 Left Shift by 30 is bitShift overflow to SignedInt - assert_equal(-3221225472, -3 << 30) + # Overflow to Fixnum + assert_float 9223372036854775808.0, 1 << 63 + assert_float(-13835058055282163712.0, -3 << 62) end assert('Integer#>>', '15.2.8.3.13') do -- cgit v1.2.3 From 198683e914ebaceba7b989c6592f871ac8fe5aa0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 27 Sep 2019 17:13:57 +0900 Subject: Simplify arguments check in `String#rindex` Also fix document about type of the first argument. --- src/string.c | 67 ++++++++++++++++++-------------------------------------- test/t/string.rb | 8 +++++++ 2 files changed, 29 insertions(+), 46 deletions(-) (limited to 'test') diff --git a/src/string.c b/src/string.c index b49fdfc2e..1428ea780 100644 --- a/src/string.c +++ b/src/string.c @@ -1977,21 +1977,17 @@ mrb_str_reverse(mrb_state *mrb, mrb_value str) /* 15.2.10.5.31 */ /* * call-seq: - * str.rindex(substring [, fixnum]) => fixnum or nil - * str.rindex(fixnum [, fixnum]) => fixnum or nil - * str.rindex(regexp [, fixnum]) => fixnum or nil + * str.rindex(substring [, offset]) => fixnum or nil * - * Returns the index of the last occurrence of the given substring, - * character (fixnum), or pattern (regexp) in str. Returns - * nil if not found. If the second parameter is present, it - * specifies the position in the string to end the search---characters beyond - * this point will not be considered. + * Returns the index of the last occurrence of the given substring. + * Returns nil if not found. If the second parameter is + * present, it specifies the position in the string to end the + * search---characters beyond this point will not be considered. * * "hello".rindex('e') #=> 1 * "hello".rindex('l') #=> 3 * "hello".rindex('a') #=> nil - * "hello".rindex(101) #=> 1 - * "hello".rindex(/[aeiou]/, -2) #=> 1 + * "hello".rindex('l', 2) #=> 2 */ static mrb_value mrb_str_rindex(mrb_state *mrb, mrb_value str) @@ -1999,46 +1995,25 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) mrb_value sub; mrb_int pos, len = RSTRING_CHAR_LEN(str); - switch (mrb_get_args(mrb, "|oi", &sub, &pos)) { - case 0: - sub = mrb_nil_value(); - /* fall through */ - case 1: - pos = len; - break; - case 2: + if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) { + pos = len; + } + else { + if (pos < 0) { + pos += len; if (pos < 0) { - pos += len; - if (pos < 0) { - return mrb_nil_value(); - } + return mrb_nil_value(); } - if (pos > len) pos = len; - break; + } + if (pos > len) pos = len; } pos = chars2bytes(str, 0, pos); - - switch (mrb_type(sub)) { - default: { - mrb_value tmp; - - tmp = mrb_check_string_type(mrb, sub); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %v given", sub); - } - sub = tmp; - } - /* fall through */ - case MRB_TT_STRING: - pos = str_rindex(mrb, str, sub, pos); - if (pos >= 0) { - pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); - BYTES_ALIGN_CHECK(pos); - return mrb_fixnum_value(pos); - } - break; - - } /* end of switch (TYPE(sub)) */ + pos = str_rindex(mrb, str, sub, pos); + if (pos >= 0) { + pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos); + BYTES_ALIGN_CHECK(pos); + return mrb_fixnum_value(pos); + } return mrb_nil_value(); } diff --git a/test/t/string.rb b/test/t/string.rb index 01f3da327..e1ff48312 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -554,9 +554,16 @@ end if UTF8STRING assert('String#rindex', '15.2.10.5.31') do assert_equal 0, 'abc'.rindex('a') + assert_equal 0, 'abc'.rindex('a', 3) + assert_nil 'abc'.rindex('a', -4) assert_nil 'abc'.rindex('d') + assert_equal 6, 'abcabc'.rindex('') + assert_equal 3, 'abcabc'.rindex('a') assert_equal 0, 'abcabc'.rindex('a', 1) assert_equal 3, 'abcabc'.rindex('a', 4) + assert_equal 0, 'abcabc'.rindex('a', -4) + assert_raise(ArgumentError) { "hello".rindex } + assert_raise(TypeError) { "hello".rindex(101) } end assert('String#rindex(UTF-8)', '15.2.10.5.31') do @@ -564,6 +571,7 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_nil str.rindex('さ') assert_equal 12, str.rindex('ち') assert_equal 3, str.rindex('ち', 10) + assert_equal 3, str.rindex('ち', -6) broken = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃" assert_nil broken.rindex("\x81") # "\x81" is a part of "☁" ("\xe2\x98\x81") -- cgit v1.2.3 From 882bc80dd09cd22850a8c4b24ff11d405eefe189 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 3 Oct 2019 16:59:18 +0900 Subject: Add tests for #4746 --- test/t/syntax.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test') diff --git a/test/t/syntax.rb b/test/t/syntax.rb index afb735e7f..2740789ae 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -451,6 +451,18 @@ assert('optional block argument in the rhs default expressions') do assert_nil(Proc.new {|foo = foo| foo}.call) end +assert('local variable definition in default value and subsequent arguments') do + def m(a = b = 1, c) [a, b, c] end + assert_equal([1, 1, :c], m(:c)) + assert_equal([:a, nil, :c], m(:a, :c)) + + def m(a = b = 1, &c) [a, b, c ? true : nil] end + assert_equal([1, 1, nil], m) + assert_equal([1, 1, true], m{}) + assert_equal([:a, nil, nil], m(:a)) + assert_equal([:a, nil, true], m(:a){}) +end + assert('multiline comments work correctly') do =begin this is a comment with nothing after begin and end @@ -654,4 +666,8 @@ assert 'keyword arguments' do result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{})) assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result) =end + + def m(a: b = 1, c:) [a, b, c] end + assert_equal([1, 1, :c], m(c: :c)) + assert_equal([:a, nil, :c], m(a: :a, c: :c)) end -- cgit v1.2.3 From 7ce5d3394706723a82d337641f960c58649e0134 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 10 Oct 2019 19:50:48 +0900 Subject: Integrate `mrb_str_inspect` and `mrb_str_dump` --- mrbgems/mruby-string-ext/test/string.rb | 1 + src/string.c | 261 ++++++++++---------------------- test/t/string.rb | 12 +- 3 files changed, 90 insertions(+), 184 deletions(-) (limited to 'test') diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 6914fe31d..3f11c00a0 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -13,6 +13,7 @@ end assert('String#dump') do assert_equal("\"\\x00\"", "\0".dump) assert_equal("\"foo\"", "foo".dump) + assert_equal('"\xe3\x82\x8b"', "る".dump) assert_nothing_raised { ("\1" * 100).dump } # regress #1210 end diff --git a/src/string.c b/src/string.c index 1428ea780..a45dee11e 100644 --- a/src/string.c +++ b/src/string.c @@ -1318,6 +1318,84 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb return src; } +#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ +#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) + +static mrb_value +str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect) +{ + const char *p, *pend; + char buf[CHAR_ESC_LEN + 1]; + mrb_value result = mrb_str_new_lit(mrb, "\""); +#ifdef MRB_UTF8_STRING + uint32_t ascii_flag = MRB_STR_ASCII; +#endif + + p = RSTRING_PTR(str); pend = RSTRING_END(str); + for (;p < pend; p++) { + unsigned char c, cc; +#ifdef MRB_UTF8_STRING + if (inspect) { + mrb_int clen = utf8len(p, pend); + if (clen > 1) { + mrb_int i; + + for (i=0; iflags |= ascii_flag; + mrb_str_ptr(result)->flags |= ascii_flag; +#endif + + return result; +} + static void mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) { @@ -2574,8 +2652,6 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self) return str; } -#define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) - /* * call-seq: * str.dump -> new_str @@ -2586,113 +2662,7 @@ mrb_str_upcase(mrb_state *mrb, mrb_value self) mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str) { - mrb_int len; - const char *p, *pend; - char *q; - struct RString *result; - - len = 2; /* "" */ - p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); - while (p < pend) { - unsigned char c = *p++; - switch (c) { - case '"': case '\\': - case '\n': case '\r': - case '\t': case '\f': - case '\013': case '\010': case '\007': case '\033': - len += 2; - break; - - case '#': - len += IS_EVSTR(p, pend) ? 2 : 1; - break; - - default: - if (ISPRINT(c)) { - len++; - } - else { - len += 4; /* \NNN */ - } - break; - } - } - - result = str_new(mrb, 0, len); - str_with_class(result, str); - p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); - q = RSTR_PTR(result); - *q++ = '"'; - while (p < pend) { - unsigned char c = *p++; - - switch (c) { - case '"': - case '\\': - *q++ = '\\'; - *q++ = c; - break; - - case '\n': - *q++ = '\\'; - *q++ = 'n'; - break; - - case '\r': - *q++ = '\\'; - *q++ = 'r'; - break; - - case '\t': - *q++ = '\\'; - *q++ = 't'; - break; - - case '\f': - *q++ = '\\'; - *q++ = 'f'; - break; - - case '\013': - *q++ = '\\'; - *q++ = 'v'; - break; - - case '\010': - *q++ = '\\'; - *q++ = 'b'; - break; - - case '\007': - *q++ = '\\'; - *q++ = 'a'; - break; - - case '\033': - *q++ = '\\'; - *q++ = 'e'; - break; - - case '#': - if (IS_EVSTR(p, pend)) *q++ = '\\'; - *q++ = '#'; - break; - - default: - if (ISPRINT(c)) { - *q++ = c; - } - else { - *q++ = '\\'; - *q++ = 'x'; - q[1] = mrb_digitmap[c % 16]; c /= 16; - q[0] = mrb_digitmap[c % 16]; - q += 2; - } - } - } - *q = '"'; - return mrb_obj_value(result); + return str_escape(mrb, str, FALSE); } MRB_API mrb_value @@ -2762,8 +2732,6 @@ mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) return mrb_str_cat_str(mrb, str1, str2); } -#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ - /* * call-seq: * str.inspect -> string @@ -2778,76 +2746,7 @@ mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str) { - const char *p, *pend; - char buf[CHAR_ESC_LEN + 1]; - mrb_value result = mrb_str_new_lit(mrb, "\""); -#ifdef MRB_UTF8_STRING - uint32_t ascii_flag = MRB_STR_ASCII; -#endif - - p = RSTRING_PTR(str); pend = RSTRING_END(str); - for (;p < pend; p++) { - unsigned char c, cc; -#ifdef MRB_UTF8_STRING - mrb_int clen; - - clen = utf8len(p, pend); - if (clen > 1) { - mrb_int i; - - for (i=0; iflags |= ascii_flag; - mrb_str_ptr(result)->flags |= ascii_flag; -#endif - - return result; + return str_escape(mrb, str, TRUE); } /* diff --git a/test/t/string.rb b/test/t/string.rb index e1ff48312..65ad13103 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -748,12 +748,18 @@ assert('String#upcase!', '15.2.10.5.43') do end assert('String#inspect', '15.2.10.5.46') do + assert_equal "\"\\x00\"", "\0".inspect + assert_equal "\"foo\"", "foo".inspect + if UTF8STRING + assert_equal '"る"', "る".inspect + else + assert_equal '"\xe3\x82\x8b"', "る".inspect + end + # should not raise an exception - regress #1210 assert_nothing_raised do - ("\1" * 100).inspect + ("\1" * 100).inspect end - - assert_equal "\"\\x00\"", "\0".inspect end # Not ISO specified -- cgit v1.2.3