Commit a16a53b5 authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto

Merge pull request #2458 from take-cheeze/min_dep_test

Support minimum dependency test.
parents 4f66de36 03866f25
...@@ -2,5 +2,6 @@ MRuby::Gem::Specification.new('mruby-enumerator') do |spec| ...@@ -2,5 +2,6 @@ MRuby::Gem::Specification.new('mruby-enumerator') do |spec|
spec.license = 'MIT' spec.license = 'MIT'
spec.author = 'mruby developers' spec.author = 'mruby developers'
spec.add_dependency('mruby-fiber', :core => 'mruby-fiber') spec.add_dependency('mruby-fiber', :core => 'mruby-fiber')
spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
spec.summary = 'Enumerator class' spec.summary = 'Enumerator class'
end end
...@@ -2,4 +2,6 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec| ...@@ -2,4 +2,6 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec|
spec.license = 'MIT' spec.license = 'MIT'
spec.author = 'mruby developers' spec.author = 'mruby developers'
spec.summary = 'extensional Hash class' spec.summary = 'extensional Hash class'
spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext'
end end
...@@ -5,13 +5,8 @@ assert('Integer#chr') do ...@@ -5,13 +5,8 @@ assert('Integer#chr') do
assert_equal("A", 65.chr) assert_equal("A", 65.chr)
assert_equal("B", 0x42.chr) assert_equal("B", 0x42.chr)
if "こんにちわ世界".size == 7 then # multibyte encoding (not support yet)
# UTF-8 gem is configured assert_raise(RangeError) { 256.chr }
assert_raise(RangeError) { 0x110000.chr }
else
# multibyte encoding (not support yet)
assert_raise(RangeError) { 256.chr }
end
end end
assert('Integer#div') do assert('Integer#div') do
......
...@@ -45,10 +45,6 @@ module MRuby ...@@ -45,10 +45,6 @@ module MRuby
MRuby::Gem.current = self MRuby::Gem.current = self
end end
def run_test_in_other_mrb_state?
not test_preload.nil? or not test_objs.empty? or not test_args.empty?
end
def setup def setup
MRuby::Gem.current = self MRuby::Gem.current = self
MRuby::Build::COMMANDS.each do |command| MRuby::Build::COMMANDS.each do |command|
...@@ -184,13 +180,15 @@ module MRuby ...@@ -184,13 +180,15 @@ module MRuby
print_gem_comment(f) print_gem_comment(f)
f.puts %Q[#include <stdlib.h>] f.puts %Q[#include <stdlib.h>]
f.puts %Q[#include "mruby.h"] f.puts %Q[#include "mruby.h"]
f.puts %Q[#include "mruby/array.h"]
f.puts %Q[#include "mruby/irep.h"] f.puts %Q[#include "mruby/irep.h"]
f.puts %Q[#include "mruby/string.h"]
f.puts %Q[#include "mruby/variable.h"] f.puts %Q[#include "mruby/variable.h"]
f.puts %Q[#include "mruby/hash.h"] unless test_args.empty? f.puts %Q[#include "mruby/hash.h"] unless test_args.empty?
end end
def test_dependencies
[@name]
end
def version_ok?(req_versions) def version_ok?(req_versions)
req_versions.map do |req| req_versions.map do |req|
cmp, ver = req.split cmp, ver = req.split
...@@ -290,7 +288,7 @@ module MRuby ...@@ -290,7 +288,7 @@ module MRuby
@ary.empty? @ary.empty?
end end
def check(build) def generate_gem_table
gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res } gem_table = @ary.reduce({}) { |res,v| res[v.name] = v; res }
default_gems = [] default_gems = []
...@@ -335,9 +333,29 @@ module MRuby ...@@ -335,9 +333,29 @@ module MRuby
fail "Conflicts of gem `#{g.name}` found: #{cfls.join ', '}" unless cfls.empty? fail "Conflicts of gem `#{g.name}` found: #{cfls.join ', '}" unless cfls.empty?
end end
class << gem_table gem_table
end
def tsort_dependencies ary, table, all_dependency_listed = false
unless all_dependency_listed
left = ary.dup
until left.empty?
v = left.pop
table[v].dependencies.each do |dep|
left.push dep[:gem]
ary.push dep[:gem]
end
end
end
ary.uniq!
table.instance_variable_set :@root_gems, ary
class << table
include TSort include TSort
alias tsort_each_node each_key def tsort_each_node &b
@root_gems.each &b
end
def tsort_each_child(n, &b) def tsort_each_child(n, &b)
fetch(n).dependencies.each do |v| fetch(n).dependencies.each do |v|
b.call v[:gem] b.call v[:gem]
...@@ -346,10 +364,16 @@ module MRuby ...@@ -346,10 +364,16 @@ module MRuby
end end
begin begin
@ary = gem_table.tsort.map { |v| gem_table[v] } table.tsort.map { |v| table[v] }
rescue TSort::Cyclic => e rescue TSort::Cyclic => e
fail "Circular mrbgem dependency found: #{e.message}" fail "Circular mrbgem dependency found: #{e.message}"
end end
end
def check(build)
gem_table = generate_gem_table
@ary = tsort_dependencies gem_table.keys, gem_table, true
each do |g| each do |g|
import_include_paths(g) import_include_paths(g)
......
MRuby.each_target do MRuby.each_target do
no_mrb_open_test_gem = [] gem_table = gems.generate_gem_table
gems.each do |g| gems.each do |g|
unless g.run_test_in_other_mrb_state?
no_mrb_open_test_gem << g
next
end
test_rbobj = g.test_rbireps.ext(exts.object) test_rbobj = g.test_rbireps.ext(exts.object)
dep_list = gems.tsort_dependencies g.test_dependencies, gem_table
file test_rbobj => g.test_rbireps file test_rbobj => g.test_rbireps
file g.test_rbireps => [g.test_rbfiles].flatten + [g.build.mrbcfile, __FILE__] do |t| file g.test_rbireps => [g.test_rbfiles].flatten + [File.join(g.dir, 'mrbgem.rake'), g.build.mrbcfile, __FILE__, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t|
open(t.name, 'w') do |f| open(t.name, 'w') do |f|
g.print_gem_test_header(f) g.print_gem_test_header(f)
test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir|
...@@ -33,21 +29,32 @@ MRuby.each_target do ...@@ -33,21 +29,32 @@ MRuby.each_target do
g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}"
end end
f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty? f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty?
dep_list.each do |d|
f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb_state *mrb);]
f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_final(mrb_state *mrb);]
end
f.puts %Q[void mrb_init_test_driver(mrb_state *mrb);]
f.puts %Q[void mrb_t_pass_result(mrb_state *dst, mrb_state *src);]
f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {]
unless g.test_rbfiles.empty? unless g.test_rbfiles.empty?
f.puts %Q[ mrb_state *mrb2;] f.puts %Q[ mrb_state *mrb2;]
if g.test_args.empty? if g.test_args.empty?
f.puts %Q[ mrb_value val1, val2, val3, ary1, ary2;] f.puts %Q[ mrb_value verbose;]
else else
f.puts %Q[ mrb_value val1, val2, val3, ary1, ary2, test_args_hash;] f.puts %Q[ mrb_value verbose, test_args_hash;]
end end
f.puts %Q[ int ai;] f.puts %Q[ int ai;]
g.test_rbfiles.count.times do |i| g.test_rbfiles.count.times do |i|
f.puts %Q[ ai = mrb_gc_arena_save(mrb);] f.puts %Q[ ai = mrb_gc_arena_save(mrb);]
f.puts %Q[ mrb2 = mrb_open();] f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);]
f.puts %Q[ val3 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"));] dep_list.each do |d|
f.puts %Q[ if (mrb_test(val3)) {] f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);]
f.puts %Q[ mrb_gv_set(mrb2, mrb_intern_lit(mrb2, "$mrbtest_verbose"), val3);] f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);]
end
f.puts %Q[ mrb_init_test_driver(mrb2);]
f.puts %Q[ verbose = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"));]
f.puts %Q[ if (mrb_test(verbose)) {]
f.puts %Q[ mrb_gv_set(mrb2, mrb_intern_lit(mrb2, "$mrbtest_verbose"), verbose);]
f.puts %Q[ }] f.puts %Q[ }]
if test_preload.nil? if test_preload.nil?
f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);]
...@@ -73,30 +80,9 @@ MRuby.each_target do ...@@ -73,30 +80,9 @@ MRuby.each_target do
f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] unless g.test_objs.empty? f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] unless g.test_objs.empty?
f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});] f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});]
f.puts %Q[ if (mrb2->exc) {]
f.puts %Q[ mrb_print_error(mrb2);]
f.puts %Q[ exit(EXIT_FAILURE);]
f.puts %Q[ }]
f.puts %Q[ ] f.puts %Q[ ]
%w(ok_test ko_test kill_test).each do |vname| f.puts %Q[ mrb_t_pass_result(mrb, mrb2);]
f.puts %Q[ val2 = mrb_gv_get(mrb2, mrb_intern_lit(mrb2, "$#{vname}"));]
f.puts %Q[ if (mrb_fixnum_p(val2)) {]
f.puts %Q[ val1 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$#{vname}"));]
f.puts %Q[ mrb_gv_set(mrb, mrb_intern_lit(mrb, "$#{vname}"), mrb_fixnum_value(mrb_fixnum(val1) + mrb_fixnum(val2)));]
f.puts %Q[ }\n]
end
f.puts %Q[ ary2 = mrb_gv_get(mrb2, mrb_intern_lit(mrb2, "$asserts"));]
f.puts %Q[ if (mrb_test(ary2)) {]
f.puts %Q[ ary1 = mrb_gv_get(mrb, mrb_intern_lit(mrb, "$asserts"));]
f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);]
f.puts %Q[ ]
f.puts %Q[ while (mrb_test(val2)) {]
f.puts %Q[ mrb_ary_push(mrb, ary1, mrb_str_new(mrb, RSTRING_PTR(val2), RSTRING_LEN(val2)));]
f.puts %Q[ val2 = mrb_ary_shift(mrb2, ary2);]
f.puts %Q[ }]
f.puts %Q[ }]
f.puts %Q[ mrb_close(mrb2);] f.puts %Q[ mrb_close(mrb2);]
f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] f.puts %Q[ mrb_gc_arena_restore(mrb, ai);]
end end
...@@ -104,44 +90,5 @@ MRuby.each_target do ...@@ -104,44 +90,5 @@ MRuby.each_target do
f.puts %Q[}] f.puts %Q[}]
end end
end end
end
no_mrb_open_test = "#{build_dir}/test/no_mrb_open_test"
no_mrb_open_test_rbfiles = no_mrb_open_test_gem.reduce([]) { |res, v|
res += v.test_rbfiles
}
if no_mrb_open_test_rbfiles.empty?
no_mrb_open_test_rbfiles << "#{MRUBY_ROOT}/test/no_mrb_open_test_dummy.rb"
end
no_mrb_open_test_lib = no_mrb_open_test.ext(exts.object)
file no_mrb_open_test_lib => "#{no_mrb_open_test}.c"
file "#{no_mrb_open_test}.c" => no_mrb_open_test_rbfiles + [MRUBY_CONFIG, __FILE__] do |t|
open(t.name, 'w') do |f|
f.puts %Q[/*]
f.puts %Q[ * This file contains a test code for following gems:]
no_mrb_open_test_gem.each { |g| f.puts %Q[ * #{g.name}] }
f.puts %Q[ *]
f.puts %Q[ * IMPORTANT:]
f.puts %Q[ * This file was generated!]
f.puts %Q[ * All manual changes will get lost.]
f.puts %Q[ */]
f.puts %Q[]
f.puts %Q[\#include "mruby.h"]
f.puts %Q[\#include "mruby/irep.h"]
f.puts %Q[]
mrbc.run f, no_mrb_open_test_rbfiles, "no_mrb_open_gem_test_irep"
f.puts %Q[]
f.puts %Q[void no_mrb_open_mrbgem_test(mrb_state *mrb) {]
f.puts %Q[ mrb_load_irep(mrb, no_mrb_open_gem_test_irep);]
f.puts %Q[}]
end
end end
end end
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "mruby/compile.h" #include "mruby/compile.h"
#include "mruby/string.h" #include "mruby/string.h"
#include "mruby/variable.h" #include "mruby/variable.h"
#include "mruby/array.h"
void void
mrb_init_mrbtest(mrb_state *); mrb_init_mrbtest(mrb_state *);
...@@ -81,12 +82,62 @@ mrb_t_printstr(mrb_state *mrb, mrb_value self) ...@@ -81,12 +82,62 @@ mrb_t_printstr(mrb_state *mrb, mrb_value self)
return argv; return argv;
} }
void
mrb_init_test_driver(mrb_state *mrb)
{
struct RClass *krn, *mrbtest;
krn = mrb->kernel_module;
mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1));
mrbtest = mrb_define_module(mrb, "Mrbtest");
mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX));
mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN));
mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT));
}
void
mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src)
{
mrb_value res_src;
if (mrb_src->exc) {
mrb_print_error(mrb_src);
exit(EXIT_FAILURE);
}
#define TEST_COUNT_PASS(name) \
do { \
res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$" #name)); \
if (mrb_fixnum_p(res_src)) { \
mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name)); \
mrb_gv_set(mrb_dst, mrb_intern_lit(mrb_dst, "$" #name), mrb_fixnum_value(mrb_fixnum(res_dst) + mrb_fixnum(res_src))); \
} \
} while (FALSE) \
TEST_COUNT_PASS(ok_test);
TEST_COUNT_PASS(ko_test);
TEST_COUNT_PASS(kill_test);
#undef TEST_COUNT_PASS
res_src = mrb_gv_get(mrb_src, mrb_intern_lit(mrb_src, "$asserts"));
if (mrb_array_p(res_src)) {
mrb_int i;
mrb_value res_dst = mrb_gv_get(mrb_dst, mrb_intern_lit(mrb_dst, "$asserts"));
for (i = 0; i < RARRAY_LEN(res_src); ++i) {
mrb_value val_src = RARRAY_PTR(res_src)[i];
mrb_ary_push(mrb_dst, res_dst, mrb_str_new(mrb_dst, RSTRING_PTR(val_src), RSTRING_LEN(val_src)));
}
}
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
mrb_state *mrb; mrb_state *mrb;
struct RClass *krn;
struct RClass *mrbtest;
int ret; int ret;
print_hint(); print_hint();
...@@ -103,15 +154,7 @@ main(int argc, char **argv) ...@@ -103,15 +154,7 @@ main(int argc, char **argv)
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value()); mrb_gv_set(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"), mrb_true_value());
} }
krn = mrb->kernel_module; mrb_init_test_driver(mrb);
mrb_define_method(mrb, krn, "__t_printstr__", mrb_t_printstr, MRB_ARGS_REQ(1));
mrbtest = mrb_define_module(mrb, "Mrbtest");
mrb_define_const(mrb, mrbtest, "FIXNUM_MAX", mrb_fixnum_value(MRB_INT_MAX));
mrb_define_const(mrb, mrbtest, "FIXNUM_MIN", mrb_fixnum_value(MRB_INT_MIN));
mrb_define_const(mrb, mrbtest, "FIXNUM_BIT", mrb_fixnum_value(MRB_INT_BIT));
mrb_init_mrbtest(mrb); mrb_init_mrbtest(mrb);
ret = eval_test(mrb); ret = eval_test(mrb);
mrb_close(mrb); mrb_close(mrb);
......
...@@ -6,15 +6,26 @@ extern const uint8_t mrbtest_assert_irep[]; ...@@ -6,15 +6,26 @@ extern const uint8_t mrbtest_assert_irep[];
extern const uint8_t mrbtest_irep[]; extern const uint8_t mrbtest_irep[];
void mrbgemtest_init(mrb_state* mrb); void mrbgemtest_init(mrb_state* mrb);
void mrb_init_test_driver(mrb_state* mrb);
void mrb_t_pass_result(mrb_state *mrb_dst, mrb_state *mrb_src);
void void
mrb_init_mrbtest(mrb_state *mrb) mrb_init_mrbtest(mrb_state *mrb)
{ {
mrb_state *core_test;
mrb_load_irep(mrb, mrbtest_assert_irep); mrb_load_irep(mrb, mrbtest_assert_irep);
mrb_load_irep(mrb, mrbtest_irep);
core_test = mrb_open_core(mrb_default_allocf, NULL);
mrb_init_test_driver(core_test);
mrb_load_irep(core_test, mrbtest_assert_irep);
mrb_load_irep(core_test, mrbtest_irep);
mrb_t_pass_result(mrb, core_test);
#ifndef DISABLE_GEMS #ifndef DISABLE_GEMS
mrbgemtest_init(mrb); mrbgemtest_init(mrb);
#endif #endif
if (mrb->exc) { if (mrb->exc) {
mrb_print_error(mrb); mrb_print_error(mrb);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
......
...@@ -12,11 +12,12 @@ MRuby.each_target do ...@@ -12,11 +12,12 @@ MRuby.each_target do
ass_lib = ass_c.ext(exts.object) ass_lib = ass_c.ext(exts.object)
mrbtest_lib = libfile("#{current_build_dir}/mrbtest") mrbtest_lib = libfile("#{current_build_dir}/mrbtest")
gem_test_files = gems.select { |g| g.run_test_in_other_mrb_state? }.map { |g| g.test_rbireps.ext(exts.object) } mrbtest_objs = gems.map do |v|
file mrbtest_lib => [mlib, ass_lib, gems.map(&:test_objs), gem_test_files].flatten do |t| v.test_objs + [v.test_rbireps.ext(exts.object)]
end
file mrbtest_lib => [mlib, ass_lib] + mrbtest_objs do |t|
archiver.run t.name, t.prerequisites archiver.run t.name, t.prerequisites
end end
file mrbtest_lib => "#{build_dir}/test/no_mrb_open_test.c".ext(exts.object)
unless build_mrbtest_lib_only? unless build_mrbtest_lib_only?
driver_obj = objfile("#{current_build_dir}/driver") driver_obj = objfile("#{current_build_dir}/driver")
...@@ -55,16 +56,12 @@ MRuby.each_target do ...@@ -55,16 +56,12 @@ MRuby.each_target do
f.puts IO.read(init) f.puts IO.read(init)
mrbc.run f, mrbs, 'mrbtest_irep' mrbc.run f, mrbs, 'mrbtest_irep'
gems.each do |g| gems.each do |g|
next unless g.run_test_in_other_mrb_state?
f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);]
end end
f.puts %Q[void no_mrb_open_mrbgem_test(mrb_state *mrb);]
f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {]
gems.each do |g| gems.each do |g|
next unless g.run_test_in_other_mrb_state?
f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);]
end end
f.puts %Q[ no_mrb_open_mrbgem_test(mrb);]
f.puts %Q[}] f.puts %Q[}]
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment