all: Remove tinytest component.
With the recent qemu (d9a0fdda9a
and0426934969
) and zephyr (05cad7b56f
) changes to how their tests are run, two things became unused: - The tinytest framework, which embedded a set of tests and their expected output within firmware, so these tests could be run stand-alone. - The `--write-exp` and `--list-tests` options to `tests/run-tests.py`, which were needed primarily to generated the expected test output for tinytest (also the associated `tests/run-tests-exp.py/.sh` scripts are now unused). This commit removes the tinytest component and all its helper code. This eliminates a maintenance burden. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
5d8878b582
commit
067ef81cd0
1
LICENSE
1
LICENSE
|
@ -59,7 +59,6 @@ used during the build process and is not part of the compiled source code.
|
||||||
/pico-sdk (BSD-3-clause)
|
/pico-sdk (BSD-3-clause)
|
||||||
/re15 (BSD-3-clause)
|
/re15 (BSD-3-clause)
|
||||||
/stm32lib (BSD-3-clause)
|
/stm32lib (BSD-3-clause)
|
||||||
/tinytest (BSD-3-clause)
|
|
||||||
/tinyusb (MIT)
|
/tinyusb (MIT)
|
||||||
/uzlib (Zlib)
|
/uzlib (Zlib)
|
||||||
/wiznet5k (MIT)
|
/wiznet5k (MIT)
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
Tinytest is a tiny little test framework written in C by Nick Mathewson.
|
|
||||||
|
|
||||||
It is distributed under the 3-clause BSD license. You can use it in
|
|
||||||
your own programs so long as you follow the license's conditions.
|
|
||||||
|
|
||||||
It's been tested on Windows, Mac, and many of the free Unixes.
|
|
||||||
|
|
||||||
It knows how to fork before running certain tests, and it makes
|
|
||||||
text-mode output in a format I like.
|
|
||||||
|
|
||||||
For info on how to use it, check out tinytest_demo.c.
|
|
||||||
|
|
||||||
You can get the latest version using Git, by pulling from
|
|
||||||
git://github.com/nmathewson/tinytest.git
|
|
||||||
|
|
||||||
Patches are welcome. Patches that turn this from tinytest to hugetest
|
|
||||||
will not be applied. If you want a huge test framework, use CUnit.
|
|
||||||
|
|
|
@ -1,474 +0,0 @@
|
||||||
/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
#ifdef TINYTEST_LOCAL
|
|
||||||
#include "tinytest_local.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifndef NO_FORKING
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
|
|
||||||
#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
|
|
||||||
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
|
|
||||||
/* Workaround for a stupid bug in OSX 10.6 */
|
|
||||||
#define FORK_BREAKS_GCOV
|
|
||||||
#include <vproc.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !NO_FORKING */
|
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
#define __attribute__(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "tinytest.h"
|
|
||||||
#include "tinytest_macros.h"
|
|
||||||
|
|
||||||
#define LONGEST_TEST_NAME 16384
|
|
||||||
|
|
||||||
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
|
|
||||||
static int n_ok = 0; /**< Number of tests that have passed */
|
|
||||||
static int n_bad = 0; /**< Number of tests that have failed. */
|
|
||||||
static int n_skipped = 0; /**< Number of tests that have been skipped. */
|
|
||||||
|
|
||||||
static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
|
|
||||||
static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
|
|
||||||
static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
|
|
||||||
const char *verbosity_flag = "";
|
|
||||||
|
|
||||||
const struct testlist_alias_t *cfg_aliases=NULL;
|
|
||||||
|
|
||||||
enum outcome { SKIP=2, OK=1, FAIL=0 };
|
|
||||||
static enum outcome cur_test_outcome = 0;
|
|
||||||
const char *cur_test_prefix = NULL; /**< prefix of the current test group */
|
|
||||||
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
|
|
||||||
const char *cur_test_name = NULL;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* Copy of argv[0] for win32. */
|
|
||||||
static char commandname[MAX_PATH+1];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void usage(struct testgroup_t *groups, int list_groups)
|
|
||||||
__attribute__((noreturn));
|
|
||||||
static int process_test_option(struct testgroup_t *groups, const char *test);
|
|
||||||
|
|
||||||
static enum outcome
|
|
||||||
testcase_run_bare_(const struct testcase_t *testcase)
|
|
||||||
{
|
|
||||||
void *env = NULL;
|
|
||||||
int outcome;
|
|
||||||
if (testcase->setup) {
|
|
||||||
env = testcase->setup->setup_fn(testcase);
|
|
||||||
if (!env)
|
|
||||||
return FAIL;
|
|
||||||
else if (env == (void*)TT_SKIP)
|
|
||||||
return SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_test_outcome = OK;
|
|
||||||
testcase->fn(env);
|
|
||||||
outcome = cur_test_outcome;
|
|
||||||
|
|
||||||
if (testcase->setup) {
|
|
||||||
if (testcase->setup->cleanup_fn(testcase, env) == 0)
|
|
||||||
outcome = FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return outcome;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAGIC_EXITCODE 42
|
|
||||||
|
|
||||||
#ifndef NO_FORKING
|
|
||||||
|
|
||||||
static enum outcome
|
|
||||||
testcase_run_forked_(const struct testgroup_t *group,
|
|
||||||
const struct testcase_t *testcase)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
|
|
||||||
we'll invoke our own exe (whose name we recall from the command
|
|
||||||
line) with a command line that tells it to run just the test we
|
|
||||||
want, and this time without forking.
|
|
||||||
|
|
||||||
(No, threads aren't an option. The whole point of forking is to
|
|
||||||
share no state between tests.)
|
|
||||||
*/
|
|
||||||
int ok;
|
|
||||||
char buffer[LONGEST_TEST_NAME+256];
|
|
||||||
STARTUPINFOA si;
|
|
||||||
PROCESS_INFORMATION info;
|
|
||||||
DWORD exitcode;
|
|
||||||
|
|
||||||
if (!in_tinytest_main) {
|
|
||||||
printf("\nERROR. On Windows, testcase_run_forked_ must be"
|
|
||||||
" called from within tinytest_main.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
if (opt_verbosity>0)
|
|
||||||
printf("[forking] ");
|
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
|
|
||||||
commandname, verbosity_flag, group->prefix, testcase->name);
|
|
||||||
|
|
||||||
memset(&si, 0, sizeof(si));
|
|
||||||
memset(&info, 0, sizeof(info));
|
|
||||||
si.cb = sizeof(si);
|
|
||||||
|
|
||||||
ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
|
|
||||||
0, NULL, NULL, &si, &info);
|
|
||||||
if (!ok) {
|
|
||||||
printf("CreateProcess failed!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
WaitForSingleObject(info.hProcess, INFINITE);
|
|
||||||
GetExitCodeProcess(info.hProcess, &exitcode);
|
|
||||||
CloseHandle(info.hProcess);
|
|
||||||
CloseHandle(info.hThread);
|
|
||||||
if (exitcode == 0)
|
|
||||||
return OK;
|
|
||||||
else if (exitcode == MAGIC_EXITCODE)
|
|
||||||
return SKIP;
|
|
||||||
else
|
|
||||||
return FAIL;
|
|
||||||
#else
|
|
||||||
int outcome_pipe[2];
|
|
||||||
pid_t pid;
|
|
||||||
(void)group;
|
|
||||||
|
|
||||||
if (pipe(outcome_pipe))
|
|
||||||
perror("opening pipe");
|
|
||||||
|
|
||||||
if (opt_verbosity>0)
|
|
||||||
printf("[forking] ");
|
|
||||||
pid = fork();
|
|
||||||
#ifdef FORK_BREAKS_GCOV
|
|
||||||
vproc_transaction_begin(0);
|
|
||||||
#endif
|
|
||||||
if (!pid) {
|
|
||||||
/* child. */
|
|
||||||
int test_r, write_r;
|
|
||||||
char b[1];
|
|
||||||
close(outcome_pipe[0]);
|
|
||||||
test_r = testcase_run_bare_(testcase);
|
|
||||||
assert(0<=(int)test_r && (int)test_r<=2);
|
|
||||||
b[0] = "NYS"[test_r];
|
|
||||||
write_r = (int)write(outcome_pipe[1], b, 1);
|
|
||||||
if (write_r != 1) {
|
|
||||||
perror("write outcome to pipe");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
return FAIL; /* unreachable */
|
|
||||||
} else {
|
|
||||||
/* parent */
|
|
||||||
int status, r;
|
|
||||||
char b[1];
|
|
||||||
/* Close this now, so that if the other side closes it,
|
|
||||||
* our read fails. */
|
|
||||||
close(outcome_pipe[1]);
|
|
||||||
r = (int)read(outcome_pipe[0], b, 1);
|
|
||||||
if (r == 0) {
|
|
||||||
printf("[Lost connection!] ");
|
|
||||||
return 0;
|
|
||||||
} else if (r != 1) {
|
|
||||||
perror("read outcome from pipe");
|
|
||||||
}
|
|
||||||
waitpid(pid, &status, 0);
|
|
||||||
close(outcome_pipe[0]);
|
|
||||||
return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !NO_FORKING */
|
|
||||||
|
|
||||||
int
|
|
||||||
testcase_run_one(const struct testgroup_t *group,
|
|
||||||
const struct testcase_t *testcase)
|
|
||||||
{
|
|
||||||
enum outcome outcome;
|
|
||||||
|
|
||||||
if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
|
|
||||||
if (opt_verbosity>0)
|
|
||||||
printf("%s%s: %s\n",
|
|
||||||
group->prefix, testcase->name,
|
|
||||||
(testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
|
|
||||||
++n_skipped;
|
|
||||||
return SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_verbosity>0 && !opt_forked) {
|
|
||||||
printf("%s%s: ", group->prefix, testcase->name);
|
|
||||||
} else {
|
|
||||||
if (opt_verbosity==0) printf(".");
|
|
||||||
cur_test_prefix = group->prefix;
|
|
||||||
cur_test_name = testcase->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_FORKING
|
|
||||||
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
|
|
||||||
outcome = testcase_run_forked_(group, testcase);
|
|
||||||
} else {
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
outcome = testcase_run_bare_(testcase);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outcome == OK) {
|
|
||||||
++n_ok;
|
|
||||||
if (opt_verbosity>0 && !opt_forked)
|
|
||||||
puts(opt_verbosity==1?"OK":"");
|
|
||||||
} else if (outcome == SKIP) {
|
|
||||||
++n_skipped;
|
|
||||||
if (opt_verbosity>0 && !opt_forked)
|
|
||||||
puts("SKIPPED");
|
|
||||||
} else {
|
|
||||||
++n_bad;
|
|
||||||
if (!opt_forked)
|
|
||||||
printf("\n [%s FAILED]\n", testcase->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_forked) {
|
|
||||||
exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
|
|
||||||
return 1; /* unreachable */
|
|
||||||
} else {
|
|
||||||
return (int)outcome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
size_t length = LONGEST_TEST_NAME;
|
|
||||||
char fullname[LONGEST_TEST_NAME];
|
|
||||||
int found=0;
|
|
||||||
if (strstr(arg, ".."))
|
|
||||||
length = strstr(arg,"..")-arg;
|
|
||||||
for (i=0; groups[i].prefix; ++i) {
|
|
||||||
for (j=0; groups[i].cases[j].name; ++j) {
|
|
||||||
struct testcase_t *testcase = &groups[i].cases[j];
|
|
||||||
snprintf(fullname, sizeof(fullname), "%s%s",
|
|
||||||
groups[i].prefix, testcase->name);
|
|
||||||
if (!flag) { /* Hack! */
|
|
||||||
printf(" %s", fullname);
|
|
||||||
if (testcase->flags & TT_OFF_BY_DEFAULT)
|
|
||||||
puts(" (Off by default)");
|
|
||||||
else if (testcase->flags & TT_SKIP)
|
|
||||||
puts(" (DISABLED)");
|
|
||||||
else
|
|
||||||
puts("");
|
|
||||||
}
|
|
||||||
if (!strncmp(fullname, arg, length)) {
|
|
||||||
if (set)
|
|
||||||
testcase->flags |= flag;
|
|
||||||
else
|
|
||||||
testcase->flags &= ~flag;
|
|
||||||
++found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
usage(struct testgroup_t *groups, int list_groups)
|
|
||||||
{
|
|
||||||
puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
|
|
||||||
puts(" Specify tests by name, or using a prefix ending with '..'");
|
|
||||||
puts(" To skip a test, prefix its name with a colon.");
|
|
||||||
puts(" To enable a disabled test, prefix its name with a plus.");
|
|
||||||
puts(" Use --list-tests for a list of tests.");
|
|
||||||
if (list_groups) {
|
|
||||||
puts("Known tests are:");
|
|
||||||
tinytest_set_flag_(groups, "..", 1, 0);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
process_test_alias(struct testgroup_t *groups, const char *test)
|
|
||||||
{
|
|
||||||
int i, j, n, r;
|
|
||||||
for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
|
|
||||||
if (!strcmp(cfg_aliases[i].name, test)) {
|
|
||||||
n = 0;
|
|
||||||
for (j = 0; cfg_aliases[i].tests[j]; ++j) {
|
|
||||||
r = process_test_option(groups, cfg_aliases[i].tests[j]);
|
|
||||||
if (r<0)
|
|
||||||
return -1;
|
|
||||||
n += r;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("No such test alias as @%s!",test);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
process_test_option(struct testgroup_t *groups, const char *test)
|
|
||||||
{
|
|
||||||
int flag = TT_ENABLED_;
|
|
||||||
int n = 0;
|
|
||||||
if (test[0] == '@') {
|
|
||||||
return process_test_alias(groups, test + 1);
|
|
||||||
} else if (test[0] == ':') {
|
|
||||||
++test;
|
|
||||||
flag = TT_SKIP;
|
|
||||||
} else if (test[0] == '+') {
|
|
||||||
++test;
|
|
||||||
++n;
|
|
||||||
if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
|
|
||||||
printf("No such test as %s!\n", test);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
if (!tinytest_set_flag_(groups, test, 1, flag)) {
|
|
||||||
printf("No such test as %s!\n", test);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tinytest_set_aliases(const struct testlist_alias_t *aliases)
|
|
||||||
{
|
|
||||||
cfg_aliases = aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
tinytest_main(int c, const char **v, struct testgroup_t *groups)
|
|
||||||
{
|
|
||||||
int i, j, n=0;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
const char *sp = strrchr(v[0], '.');
|
|
||||||
const char *extension = "";
|
|
||||||
if (!sp || stricmp(sp, ".exe"))
|
|
||||||
extension = ".exe"; /* Add an exe so CreateProcess will work */
|
|
||||||
snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
|
|
||||||
commandname[MAX_PATH]='\0';
|
|
||||||
#endif
|
|
||||||
for (i=1; i<c; ++i) {
|
|
||||||
if (v[i][0] == '-') {
|
|
||||||
if (!strcmp(v[i], "--RUNNING-FORKED")) {
|
|
||||||
opt_forked = 1;
|
|
||||||
} else if (!strcmp(v[i], "--no-fork")) {
|
|
||||||
opt_nofork = 1;
|
|
||||||
} else if (!strcmp(v[i], "--quiet")) {
|
|
||||||
opt_verbosity = -1;
|
|
||||||
verbosity_flag = "--quiet";
|
|
||||||
} else if (!strcmp(v[i], "--verbose")) {
|
|
||||||
opt_verbosity = 2;
|
|
||||||
verbosity_flag = "--verbose";
|
|
||||||
} else if (!strcmp(v[i], "--terse")) {
|
|
||||||
opt_verbosity = 0;
|
|
||||||
verbosity_flag = "--terse";
|
|
||||||
} else if (!strcmp(v[i], "--help")) {
|
|
||||||
usage(groups, 0);
|
|
||||||
} else if (!strcmp(v[i], "--list-tests")) {
|
|
||||||
usage(groups, 1);
|
|
||||||
} else {
|
|
||||||
printf("Unknown option %s. Try --help\n",v[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int r = process_test_option(groups, v[i]);
|
|
||||||
if (r<0)
|
|
||||||
return -1;
|
|
||||||
n += r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!n)
|
|
||||||
tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
|
|
||||||
|
|
||||||
#ifdef _IONBF
|
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
++in_tinytest_main;
|
|
||||||
for (i=0; groups[i].prefix; ++i)
|
|
||||||
for (j=0; groups[i].cases[j].name; ++j)
|
|
||||||
if (groups[i].cases[j].flags & TT_ENABLED_)
|
|
||||||
testcase_run_one(&groups[i],
|
|
||||||
&groups[i].cases[j]);
|
|
||||||
|
|
||||||
--in_tinytest_main;
|
|
||||||
|
|
||||||
if (opt_verbosity==0)
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
if (n_bad)
|
|
||||||
printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
|
|
||||||
n_bad+n_ok,n_skipped);
|
|
||||||
else if (opt_verbosity >= 1)
|
|
||||||
printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
|
|
||||||
|
|
||||||
return (n_bad == 0) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
tinytest_get_verbosity_(void)
|
|
||||||
{
|
|
||||||
return opt_verbosity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tinytest_set_test_failed_(void)
|
|
||||||
{
|
|
||||||
if (opt_verbosity <= 0 && cur_test_name) {
|
|
||||||
if (opt_verbosity==0) puts("");
|
|
||||||
printf("%s%s: ", cur_test_prefix, cur_test_name);
|
|
||||||
cur_test_name = NULL;
|
|
||||||
}
|
|
||||||
cur_test_outcome = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
tinytest_set_test_skipped_(void)
|
|
||||||
{
|
|
||||||
if (cur_test_outcome==OK)
|
|
||||||
cur_test_outcome = SKIP;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TINYTEST_H_INCLUDED_
|
|
||||||
#define TINYTEST_H_INCLUDED_
|
|
||||||
|
|
||||||
/** Flag for a test that needs to run in a subprocess. */
|
|
||||||
#define TT_FORK (1<<0)
|
|
||||||
/** Runtime flag for a test we've decided to skip. */
|
|
||||||
#define TT_SKIP (1<<1)
|
|
||||||
/** Internal runtime flag for a test we've decided to run. */
|
|
||||||
#define TT_ENABLED_ (1<<2)
|
|
||||||
/** Flag for a test that's off by default. */
|
|
||||||
#define TT_OFF_BY_DEFAULT (1<<3)
|
|
||||||
/** If you add your own flags, make them start at this point. */
|
|
||||||
#define TT_FIRST_USER_FLAG (1<<4)
|
|
||||||
|
|
||||||
typedef void (*testcase_fn)(void *);
|
|
||||||
|
|
||||||
struct testcase_t;
|
|
||||||
|
|
||||||
/** Functions to initialize/teardown a structure for a testcase. */
|
|
||||||
struct testcase_setup_t {
|
|
||||||
/** Return a new structure for use by a given testcase. */
|
|
||||||
void *(*setup_fn)(const struct testcase_t *);
|
|
||||||
/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
|
|
||||||
int (*cleanup_fn)(const struct testcase_t *, void *);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A single test-case that you can run. */
|
|
||||||
struct testcase_t {
|
|
||||||
const char *name; /**< An identifier for this case. */
|
|
||||||
testcase_fn fn; /**< The function to run to implement this case. */
|
|
||||||
unsigned long flags; /**< Bitfield of TT_* flags. */
|
|
||||||
const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
|
|
||||||
void *setup_data; /**< Extra data usable by setup function */
|
|
||||||
};
|
|
||||||
#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
|
|
||||||
|
|
||||||
/** A group of tests that are selectable together. */
|
|
||||||
struct testgroup_t {
|
|
||||||
const char *prefix; /**< Prefix to prepend to testnames. */
|
|
||||||
struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
|
|
||||||
};
|
|
||||||
#define END_OF_GROUPS { NULL, NULL}
|
|
||||||
|
|
||||||
struct testlist_alias_t {
|
|
||||||
const char *name;
|
|
||||||
const char **tests;
|
|
||||||
};
|
|
||||||
#define END_OF_ALIASES { NULL, NULL }
|
|
||||||
|
|
||||||
/** Implementation: called from a test to indicate failure, before logging. */
|
|
||||||
void tinytest_set_test_failed_(void);
|
|
||||||
/** Implementation: called from a test to indicate that we're skipping. */
|
|
||||||
void tinytest_set_test_skipped_(void);
|
|
||||||
/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
|
|
||||||
int tinytest_get_verbosity_(void);
|
|
||||||
/** Implementation: Set a flag on tests matching a name; returns number
|
|
||||||
* of tests that matched. */
|
|
||||||
int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long);
|
|
||||||
|
|
||||||
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
|
|
||||||
#define tinytest_skip(groups, named) \
|
|
||||||
tinytest_set_flag_(groups, named, 1, TT_SKIP)
|
|
||||||
|
|
||||||
/** Run a single testcase in a single group. */
|
|
||||||
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
|
|
||||||
|
|
||||||
void tinytest_set_aliases(const struct testlist_alias_t *aliases);
|
|
||||||
|
|
||||||
/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
|
|
||||||
as selected from the command line. */
|
|
||||||
int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,184 +0,0 @@
|
||||||
/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TINYTEST_MACROS_H_INCLUDED_
|
|
||||||
#define TINYTEST_MACROS_H_INCLUDED_
|
|
||||||
|
|
||||||
/* Helpers for defining statement-like macros */
|
|
||||||
#define TT_STMT_BEGIN do {
|
|
||||||
#define TT_STMT_END } while (0)
|
|
||||||
|
|
||||||
/* Redefine this if your test functions want to abort with something besides
|
|
||||||
* "goto end;" */
|
|
||||||
#ifndef TT_EXIT_TEST_FUNCTION
|
|
||||||
#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Redefine this if you want to note success/failure in some different way. */
|
|
||||||
#ifndef TT_DECLARE
|
|
||||||
#define TT_DECLARE(prefix, args) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
|
|
||||||
printf args ; \
|
|
||||||
TT_STMT_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Announce a failure. Args are parenthesized printf args. */
|
|
||||||
#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
|
|
||||||
|
|
||||||
/* Announce a non-failure if we're verbose. */
|
|
||||||
#define TT_BLATHER(args) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
#define TT_DIE(args) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
tinytest_set_test_failed_(); \
|
|
||||||
TT_GRIPE(args); \
|
|
||||||
TT_EXIT_TEST_FUNCTION; \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
#define TT_FAIL(args) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
tinytest_set_test_failed_(); \
|
|
||||||
TT_GRIPE(args); \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
/* Fail and abort the current test for the reason in msg */
|
|
||||||
#define tt_abort_printf(msg) TT_DIE(msg)
|
|
||||||
#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
|
|
||||||
#define tt_abort_msg(msg) TT_DIE(("%s", msg))
|
|
||||||
#define tt_abort() TT_DIE(("%s", "(Failed.)"))
|
|
||||||
|
|
||||||
/* Fail but do not abort the current test for the reason in msg. */
|
|
||||||
#define tt_failprint_f(msg) TT_FAIL(msg)
|
|
||||||
#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
|
|
||||||
#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
|
|
||||||
#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
|
|
||||||
|
|
||||||
/* End the current test, and indicate we are skipping it. */
|
|
||||||
#define tt_skip() \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
tinytest_set_test_skipped_(); \
|
|
||||||
TT_EXIT_TEST_FUNCTION; \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
#define tt_want_(b, msg, fail) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
if (!(b)) { \
|
|
||||||
tinytest_set_test_failed_(); \
|
|
||||||
TT_GRIPE(("%s",msg)); \
|
|
||||||
fail; \
|
|
||||||
} else { \
|
|
||||||
TT_BLATHER(("%s",msg)); \
|
|
||||||
} \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
|
|
||||||
#define tt_want_msg(b, msg) \
|
|
||||||
tt_want_(b, msg, );
|
|
||||||
|
|
||||||
/* Assert b and stop the test if b fails. Log msg on failure. */
|
|
||||||
#define tt_assert_msg(b, msg) \
|
|
||||||
tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
|
|
||||||
|
|
||||||
/* Assert b, but do not stop the test if b fails. */
|
|
||||||
#define tt_want(b) tt_want_msg( (b), "want("#b")")
|
|
||||||
/* Assert b, and stop the test if b fails. */
|
|
||||||
#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
|
|
||||||
|
|
||||||
#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
|
|
||||||
setup_block,cleanup_block,die_on_fail) \
|
|
||||||
TT_STMT_BEGIN \
|
|
||||||
type val1_ = (type)(a); \
|
|
||||||
type val2_ = (type)(b); \
|
|
||||||
int tt_status_ = (test); \
|
|
||||||
if (!tt_status_ || tinytest_get_verbosity_()>1) { \
|
|
||||||
printf_type print_; \
|
|
||||||
printf_type print1_; \
|
|
||||||
printf_type print2_; \
|
|
||||||
type value_ = val1_; \
|
|
||||||
setup_block; \
|
|
||||||
print1_ = print_; \
|
|
||||||
value_ = val2_; \
|
|
||||||
setup_block; \
|
|
||||||
print2_ = print_; \
|
|
||||||
TT_DECLARE(tt_status_?" OK":"FAIL", \
|
|
||||||
("assert(%s): "printf_fmt" vs "printf_fmt, \
|
|
||||||
str_test, print1_, print2_)); \
|
|
||||||
print_ = print1_; \
|
|
||||||
cleanup_block; \
|
|
||||||
print_ = print2_; \
|
|
||||||
cleanup_block; \
|
|
||||||
if (!tt_status_) { \
|
|
||||||
tinytest_set_test_failed_(); \
|
|
||||||
die_on_fail ; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
TT_STMT_END
|
|
||||||
|
|
||||||
#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \
|
|
||||||
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
|
|
||||||
{print_=value_;},{},die_on_fail)
|
|
||||||
|
|
||||||
/* Helper: assert that a op b, when cast to type. Format the values with
|
|
||||||
* printf format fmt on failure. */
|
|
||||||
#define tt_assert_op_type(a,op,b,type,fmt) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
|
|
||||||
TT_EXIT_TEST_FUNCTION)
|
|
||||||
|
|
||||||
#define tt_int_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
|
|
||||||
"%ld",TT_EXIT_TEST_FUNCTION)
|
|
||||||
|
|
||||||
#define tt_uint_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
|
|
||||||
(val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
|
|
||||||
|
|
||||||
#define tt_ptr_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
|
|
||||||
(val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
|
|
||||||
|
|
||||||
#define tt_str_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
|
|
||||||
(strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
|
|
||||||
|
|
||||||
#define tt_want_int_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
|
|
||||||
|
|
||||||
#define tt_want_uint_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
|
|
||||||
(val1_ op val2_),"%lu",(void)0)
|
|
||||||
|
|
||||||
#define tt_want_ptr_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
|
|
||||||
(val1_ op val2_),"%p",(void)0)
|
|
||||||
|
|
||||||
#define tt_want_str_op(a,op,b) \
|
|
||||||
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
|
|
||||||
(strcmp(val1_,val2_) op 0),"<%s>",(void)0)
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the MicroPython project, http://micropython.org/
|
|
||||||
*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Linaro Limited
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "py/mphal.h"
|
|
||||||
#include "py/gc.h"
|
|
||||||
#include "py/runtime.h"
|
|
||||||
#include "py/compile.h"
|
|
||||||
#include "upytesthelper.h"
|
|
||||||
|
|
||||||
#if !MICROPY_PY_SYS_PATH
|
|
||||||
#error "upytesthelper requires MICROPY_PY_SYS_PATH=1"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !MICROPY_PY_SYS_ARGV
|
|
||||||
#error "upytesthelper requires MICROPY_PY_SYS_ARGV=1"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *test_exp_output;
|
|
||||||
static int test_exp_output_len, test_rem_output_len;
|
|
||||||
static int test_failed;
|
|
||||||
static void *heap_start, *heap_end;
|
|
||||||
|
|
||||||
void upytest_set_heap(void *start, void *end) {
|
|
||||||
heap_start = start;
|
|
||||||
heap_end = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
void upytest_set_expected_output(const char *output, unsigned len) {
|
|
||||||
test_exp_output = output;
|
|
||||||
test_exp_output_len = test_rem_output_len = len;
|
|
||||||
test_failed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool upytest_is_failed(void) {
|
|
||||||
if (test_failed) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
if (test_rem_output_len != 0) {
|
|
||||||
printf("remaining len: %d\n", test_rem_output_len);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return test_rem_output_len != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MP_PLAT_PRINT_STRN() should be redirected to this function.
|
|
||||||
// It will pass-through any content to mp_hal_stdout_tx_strn_cooked()
|
|
||||||
// (the default value of MP_PLAT_PRINT_STRN), but will also match
|
|
||||||
// it to the expected output as set by upytest_set_expected_output().
|
|
||||||
// If mismatch happens, upytest_is_failed() returns true.
|
|
||||||
void upytest_output(const char *str, mp_uint_t len) {
|
|
||||||
if (!test_failed) {
|
|
||||||
if (len > test_rem_output_len) {
|
|
||||||
test_failed = true;
|
|
||||||
} else {
|
|
||||||
test_failed = memcmp(test_exp_output, str, len);
|
|
||||||
#if 0
|
|
||||||
if (test_failed) {
|
|
||||||
printf("failed after char %u, within %d chars, res: %d\n",
|
|
||||||
test_exp_output_len - test_rem_output_len, (int)len, test_failed);
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (str[i] != test_exp_output[i]) {
|
|
||||||
printf("%d %02x %02x\n", i, str[i], test_exp_output[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
test_exp_output += len;
|
|
||||||
test_rem_output_len -= len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mp_hal_stdout_tx_strn_cooked(str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void upytest_execute_test(const char *src) {
|
|
||||||
// To provide clean room for each test, interpreter and heap are
|
|
||||||
// reinitialized before running each.
|
|
||||||
gc_init(heap_start, heap_end);
|
|
||||||
mp_init();
|
|
||||||
mp_sys_path = mp_obj_new_list(0, NULL);
|
|
||||||
#if MICROPY_MODULE_FROZEN
|
|
||||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
|
|
||||||
#endif
|
|
||||||
mp_obj_list_init(mp_sys_argv, 0);
|
|
||||||
|
|
||||||
nlr_buf_t nlr;
|
|
||||||
if (nlr_push(&nlr) == 0) {
|
|
||||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
|
||||||
qstr source_name = lex->source_name;
|
|
||||||
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
|
||||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false);
|
|
||||||
mp_call_function_0(module_fun);
|
|
||||||
nlr_pop();
|
|
||||||
} else {
|
|
||||||
mp_obj_t exc = (mp_obj_t)nlr.ret_val;
|
|
||||||
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
|
|
||||||
// Assume that sys.exit() is called to skip the test.
|
|
||||||
// TODO: That can be always true, we should set up convention to
|
|
||||||
// use specific exit code as skip indicator.
|
|
||||||
tinytest_set_test_skipped_();
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
mp_obj_print_exception(&mp_plat_print, exc);
|
|
||||||
tt_abort_msg("Uncaught exception\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upytest_is_failed()) {
|
|
||||||
tinytest_set_test_failed_();
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
mp_deinit();
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the MicroPython project, http://micropython.org/
|
|
||||||
*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Linaro Limited
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "py/mpconfig.h"
|
|
||||||
#include "lib/tinytest/tinytest.h"
|
|
||||||
#include "lib/tinytest/tinytest_macros.h"
|
|
||||||
|
|
||||||
void upytest_set_heap(void *start, void *end);
|
|
||||||
void upytest_set_expected_output(const char *output, unsigned len);
|
|
||||||
void upytest_execute_test(const char *src);
|
|
||||||
void upytest_output(const char *str, mp_uint_t len);
|
|
||||||
bool upytest_is_failed(void);
|
|
|
@ -1,8 +0,0 @@
|
||||||
tinytest/.gitignore
|
|
||||||
tinytest/.travis.yml
|
|
||||||
tinytest/Makefile
|
|
||||||
tinytest/Makefile.arm-cortex-m3-qemu
|
|
||||||
tinytest/Makefile.avr
|
|
||||||
tinytest/TODO
|
|
||||||
tinytest/portable_demo.c
|
|
||||||
tinytest/tinytest_demo.c
|
|
|
@ -1,146 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os, sys
|
|
||||||
from glob import glob
|
|
||||||
from re import sub
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
|
|
||||||
def escape(s):
|
|
||||||
s = s.decode()
|
|
||||||
lookup = {
|
|
||||||
"\0": "\\0",
|
|
||||||
"\t": "\\t",
|
|
||||||
"\n": '\\n"\n"',
|
|
||||||
"\r": "\\r",
|
|
||||||
"\\": "\\\\",
|
|
||||||
'"': '\\"',
|
|
||||||
}
|
|
||||||
return '""\n"{}"'.format("".join([lookup[x] if x in lookup else x for x in s]))
|
|
||||||
|
|
||||||
|
|
||||||
def chew_filename(t):
|
|
||||||
return {"func": "test_{}_fn".format(sub(r"/|\.|-", "_", t)), "desc": t}
|
|
||||||
|
|
||||||
|
|
||||||
def script_to_map(test_file):
|
|
||||||
r = {"name": chew_filename(test_file)["func"]}
|
|
||||||
with open(test_file, "rb") as f:
|
|
||||||
r["script"] = escape(f.read())
|
|
||||||
with open(test_file + ".exp", "rb") as f:
|
|
||||||
r["output"] = escape(f.read())
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def load_profile(profile_file, test_dirs, exclude_tests):
|
|
||||||
profile_globals = {"test_dirs": test_dirs, "exclude_tests": exclude_tests}
|
|
||||||
exec(profile_file.read(), profile_globals)
|
|
||||||
return profile_globals["test_dirs"], profile_globals["exclude_tests"]
|
|
||||||
|
|
||||||
|
|
||||||
test_function = (
|
|
||||||
"void {name}(void* data) {{\n"
|
|
||||||
" static const char pystr[] = {script};\n"
|
|
||||||
" static const char exp[] = {output};\n"
|
|
||||||
' printf("\\n");\n'
|
|
||||||
" upytest_set_expected_output(exp, sizeof(exp) - 1);\n"
|
|
||||||
" upytest_execute_test(pystr);\n"
|
|
||||||
' printf("result: ");\n'
|
|
||||||
"}}"
|
|
||||||
)
|
|
||||||
|
|
||||||
testcase_struct = "struct testcase_t {name}_tests[] = {{\n{body}\n END_OF_TESTCASES\n}};"
|
|
||||||
testcase_member = ' {{ "{desc}", {func}, TT_ENABLED_, 0, 0 }},'
|
|
||||||
|
|
||||||
testgroup_struct = "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};"
|
|
||||||
testgroup_member = ' {{ "{name}", {name}_tests }},'
|
|
||||||
|
|
||||||
## XXX: may be we could have `--without <groups>` argument...
|
|
||||||
|
|
||||||
test_dirs = set(
|
|
||||||
(
|
|
||||||
"basics",
|
|
||||||
"extmod",
|
|
||||||
"float",
|
|
||||||
"micropython",
|
|
||||||
"misc",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
exclude_tests = set(
|
|
||||||
(
|
|
||||||
# pattern matching in .exp
|
|
||||||
"basics/bytes_compare3.py",
|
|
||||||
"extmod/ticks_diff.py",
|
|
||||||
"extmod/time_ms_us.py",
|
|
||||||
# unicode char issue
|
|
||||||
"extmod/json_loads.py",
|
|
||||||
# doesn't output to python stdout
|
|
||||||
"extmod/re_debug.py",
|
|
||||||
"extmod/vfs_basic.py",
|
|
||||||
"extmod/vfs_fat_ramdisk.py",
|
|
||||||
"extmod/vfs_fat_fileio.py",
|
|
||||||
"extmod/vfs_fat_fsusermount.py",
|
|
||||||
"extmod/vfs_fat_oldproto.py",
|
|
||||||
# rounding issues
|
|
||||||
"float/float_divmod.py",
|
|
||||||
# requires double precision floating point to work
|
|
||||||
"float/float2int_doubleprec_intbig.py",
|
|
||||||
"float/float_format_ints_doubleprec.py",
|
|
||||||
"float/float_parse_doubleprec.py",
|
|
||||||
# different filename in output
|
|
||||||
"micropython/emg_exc.py",
|
|
||||||
"micropython/heapalloc_traceback.py",
|
|
||||||
# don't have emergency exception buffer
|
|
||||||
"micropython/heapalloc_exc_compressed_emg_exc.py",
|
|
||||||
# pattern matching in .exp
|
|
||||||
"micropython/meminfo.py",
|
|
||||||
# needs sys stdfiles
|
|
||||||
"misc/print_exception.py",
|
|
||||||
# settrace .exp files are too large
|
|
||||||
"misc/sys_settrace_loop.py",
|
|
||||||
"misc/sys_settrace_generator.py",
|
|
||||||
"misc/sys_settrace_features.py",
|
|
||||||
# don't have f-string
|
|
||||||
"basics/string_fstring.py",
|
|
||||||
"basics/string_fstring_debug.py",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
output = []
|
|
||||||
tests = []
|
|
||||||
|
|
||||||
argparser = argparse.ArgumentParser(
|
|
||||||
description="Convert native MicroPython tests to tinytest/upytesthelper C code"
|
|
||||||
)
|
|
||||||
argparser.add_argument("--stdin", action="store_true", help="read list of tests from stdin")
|
|
||||||
argparser.add_argument("--exclude", action="append", help="exclude test by name")
|
|
||||||
argparser.add_argument(
|
|
||||||
"--profile",
|
|
||||||
type=argparse.FileType("rt", encoding="utf-8"),
|
|
||||||
help="optional profile file providing test directories and exclusion list",
|
|
||||||
)
|
|
||||||
args = argparser.parse_args()
|
|
||||||
|
|
||||||
if not args.stdin:
|
|
||||||
if args.profile:
|
|
||||||
test_dirs, exclude_tests = load_profile(args.profile, test_dirs, exclude_tests)
|
|
||||||
if args.exclude:
|
|
||||||
exclude_tests = exclude_tests.union(args.exclude)
|
|
||||||
for group in test_dirs:
|
|
||||||
tests += [test for test in glob("{}/*.py".format(group)) if test not in exclude_tests]
|
|
||||||
else:
|
|
||||||
for l in sys.stdin:
|
|
||||||
tests.append(l.rstrip())
|
|
||||||
|
|
||||||
output.extend([test_function.format(**script_to_map(test)) for test in tests])
|
|
||||||
testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests]
|
|
||||||
output.append(testcase_struct.format(name="", body="\n".join(testcase_members)))
|
|
||||||
|
|
||||||
testgroup_members = [testgroup_member.format(name=group) for group in [""]]
|
|
||||||
|
|
||||||
output.append(testgroup_struct.format(body="\n".join(testgroup_members)))
|
|
||||||
|
|
||||||
## XXX: may be we could have `--output <filename>` argument...
|
|
||||||
# Don't depend on what system locale is set, use utf8 encoding.
|
|
||||||
sys.stdout.buffer.write("\n\n".join(output).encode("utf8"))
|
|
Loading…
Reference in New Issue