static result_t run(int32_t loglevel) { if (!s_root) return 0; if (s_now != s_root) return CHECK_ERROR(CALL_E_INVALID_CALL); s_now = NULL; QuickArray<obj_ptr<_case> > stack; QuickArray<std::string> names; QuickArray<std::string> msgs; int i, j; int32_t oldlevel = 0; int32_t cnt = 0, errcnt = 0; char buf[128]; date_t da1, da2; console_base::get_loglevel(oldlevel); console_base::set_loglevel(loglevel); stack.append(s_root); da1.now(); while (stack.size()) { _case *p = stack[stack.size() - 1]; _case *p1, *p2; if (p->m_pos == 0) { for (i = 0; i < (int) p->m_hooks[HOOK_BEFORE].size(); i++) if (v8::Local<v8::Function>::New(isolate, p->m_hooks[HOOK_BEFORE][i])->Call(v8::Undefined(isolate), 0, NULL).IsEmpty()) { console_base::set_loglevel(oldlevel); clear(); return 0; } } if (p->m_pos < (int) p->m_subs.size()) { std::string str(stack.size() * 2, ' '); p1 = p->m_subs[p->m_pos++]; if (p1->m_block.IsEmpty()) { console_base::set_loglevel(oldlevel); if (stack.size() == 1) asyncLog(console_base::_INFO, ""); str.append(logger::highLight()); str.append(p1->m_name); str.append(COLOR_RESET); asyncLog(console_base::_INFO, str); console_base::set_loglevel(loglevel); stack.append(p1); continue; } for (j = 0; j < (int) stack.size(); j++) { p2 = stack[j]; for (i = 0; i < (int) p2->m_hooks[HOOK_BEFORECASE].size(); i++) if (v8::Local<v8::Function>::New(isolate, p2->m_hooks[HOOK_BEFORECASE][i])->Call(v8::Undefined(isolate), 0, NULL).IsEmpty()) { console_base::set_loglevel(oldlevel); clear(); return 0; } } cnt++; { v8::TryCatch try_catch; date_t d1, d2; d1.now(); v8::Local<v8::Function>::New(isolate, p1->m_block)->Call(v8::Undefined(isolate), 0, NULL); d2.now(); if (try_catch.HasCaught()) { sprintf(buf, "%d) ", ++errcnt); p1->m_error = true; if (loglevel > console_base::_ERROR) ReportException(try_catch, 0); else if (loglevel == console_base::_ERROR) { std::string str1(buf); for (i = 1; i < (int)stack.size(); i ++) { str1.append(stack[i]->m_name); str1.append(" ", 1); } str1.append(p1->m_name); names.append(logger::highLight() + str1 + COLOR_RESET); msgs.append(GetException(try_catch, 0)); } str.append(buf); str.append(p1->m_name); } else { double n = d2.diff(d1); str.append(logger::notice() + "\xe2\x88\x9a " COLOR_RESET); str.append(p1->m_name); if (n > s_slow / 2) { sprintf(buf, " (%dms) ", (int) n); if (n > s_slow) str.append(logger::error()); else str.append(logger::warn()); str.append(buf); str.append(COLOR_RESET); } } } console_base::set_loglevel(oldlevel); asyncLog( p1->m_error ? console_base::_ERROR : console_base::_INFO, str); console_base::set_loglevel(loglevel); for (j = (int) stack.size() - 1; j >= 0; j--) { p2 = stack[j]; for (i = (int) p2->m_hooks[HOOK_AFTERCASE].size() - 1; i >= 0; i--) if (v8::Local<v8::Function>::New(isolate, p2->m_hooks[HOOK_AFTERCASE][i])->Call(v8::Undefined(isolate), 0, NULL).IsEmpty()) { console_base::set_loglevel(oldlevel); clear(); return 0; } } } if (p->m_pos == (int)p->m_subs.size()) { for (i = (int) p->m_hooks[HOOK_AFTER].size() - 1; i >= 0; i--) if (v8::Local<v8::Function>::New(isolate, p->m_hooks[HOOK_AFTER][i])->Call(v8::Undefined(isolate), 0, NULL).IsEmpty()) { console_base::set_loglevel(oldlevel); clear(); return 0; } stack.pop(); } } console_base::set_loglevel(oldlevel); asyncLog(console_base::_INFO, ""); if (errcnt == 0) { da2.now(); sprintf(buf, (logger::notice() + " \xe2\x88\x9a %d tests completed" COLOR_RESET " (%dms)").c_str(), cnt, (int) da2.diff(da1)); asyncLog(console_base::_INFO, buf); } else { sprintf(buf, (logger::error() + " × %d of %d tests failed" COLOR_RESET).c_str(), errcnt, cnt); asyncLog(console_base::_ERROR, buf); } asyncLog(console_base::_INFO, ""); for (i = 0; i < (int) msgs.size(); i++) { asyncLog(console_base::_INFO, names[i]); asyncLog(console_base::_ERROR, msgs[i]); } clear(); return 0; }