1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include "stdafx.h"
#include "Util.h"
#include "Compiler/Debug.h"
BEGIN_TEST(ActiveBasic, Reload) {
// Check basic reloading of active functions:
Package *reload = gEngine().package(S("tests.reload"));
const char contents[] =
"Nat activeBasic(Nat times) {\n"
" Nat sum = beforeItem();\n"
" for (Nat i = 0; i < times; i++) {\n"
" sum *= 10;\n"
" sum += nextItem();\n"
" }\n"
" sum += afterItem();\n"
" return sum;\n"
"}\n"
"\n"
"Nat nextItem() {\n"
" yield();\n"
" 5;\n"
"}\n"
"\n"
"Nat beforeItem() { 5; }\n"
"\n"
"Nat afterItem() { 10000; }\n";
// Note: This both verifies that the original code is run, but also that it is compiled before
// we start. If it is not compiled, it invalidates our timing-based assumptions.
CHECK_EQ(runFn<Nat>(S("tests.reload.activeBasic"), Nat(4)), 9);
os::Future<Nat> result;
spawnFn(result, S("tests.reload.activeBasic"), Nat(4));
// Let the function run until its first 'yield':
os::UThread::leave();
// Replace everything:
reloadFile(reload, S("active_basic.bs"), contents);
// Now, let it run to completion and see what we get!
// Note: Without replacing active functions, we should get 10017, with it we should get 2555.
CHECK_EQ(result.result(), 15555);
} END_TEST
BEGIN_TEST(ActiveException, Reload) {
// Check so that we can throw exceptions through an updated function:
Package *reload = gEngine().package(S("tests.reload"));
const char contents[] =
"use core:debug;\n"
"\n"
"Int activeException() {\n"
" DbgVal val(10);\n"
" exceptionHelper();\n"
" val.v;\n"
"}\n"
"\n"
"void exceptionHelper() {\n"
" yield();\n"
" throw NotSupported(\"test\");\n"
"}\n";
debug::DbgVal::clear();
CHECK_ERROR(runFn<Int>(S("tests.reload.activeException")), NotSupported);
CHECK(debug::DbgVal::clear());
os::Future<Int> result;
spawnFn(result, S("tests.reload.activeException"));
os::UThread::leave();
// Replace!
reloadFile(reload, S("active_exception.bs"), contents);
// Make sure that it still throws, that the exception is propagated properly, and that we can clean up as expected.
CHECK_ERROR(result.result(), NotSupported);
CHECK(debug::DbgVal::clear());
} END_TEST
BEGIN_TEST(ActiveNewVars, Reload) {
// Check so that we can re-shuffle the stack frame of a function.
Package *reload = gEngine().package(S("tests.reload"));
const char contents[] =
"use core:debug;\n"
"\n"
"Nat activeNewVars(Nat max) {\n"
" Nat result = 0;\n"
" Nat times = 0;\n"
" DbgVal val(0);\n"
" while (result < max) {\n"
" Nat v = newVarsNext();\n"
" result += v;\n"
" if (++times >= 4)\n"
" break;\n"
" }\n"
" result;\n"
"}\n"
"\n"
"Nat newVarsNext() {\n"
" yield();\n"
" 10;\n"
"}\n";
debug::DbgVal::clear();
CHECK_EQ(runFn<Nat>(S("tests.reload.activeNewVars"), Nat(100)), 100);
CHECK(debug::DbgVal::clear());
os::Future<Nat> result;
spawnFn(result, S("tests.reload.activeNewVars"), Nat(100));
// Let it run for a bit, so that we see a difference from just starting the function from zero.
for (Nat i = 0; i < 2; i++)
os::UThread::leave();
reloadFile(reload, S("active_newvars.bs"), contents);
CHECK_EQ(result.result(), 50);
CHECK(debug::DbgVal::clear());
// Running it from scratch should give zero.
CHECK_EQ(runFn<Nat>(S("tests.reload.activeNewVars"), Nat(100)), 40);
CHECK(debug::DbgVal::clear());
} END_TEST
|