cosmopolitan/libc/testlib/subprocess.h
Justine Tunney b41f91c658
Greatly expand system() shell code features
The cosmopolitan command interpreter now has 13 builtin commands,
variable support, support for ; / && / || syntax, asynchronous support,
and plenty of unit tests with bug fixes.

This change fixes a bug in posix_spawn() with null envp arg. strace
logging now uses atomic writes for scatter functions. Breaking change
renaming GetCpuCount() to _getcpucount(). TurfWar is now updated to use
the new token bucket algorithm. WIN32 affinity masks now inherit across
fork() and execve().
2022-10-11 21:30:31 -07:00

83 lines
2.1 KiB
C

#ifndef COSMOPOLITAN_LIBC_TESTLIB_SUBPROCESS_H_
#define COSMOPOLITAN_LIBC_TESTLIB_SUBPROCESS_H_
#include "libc/calls/calls.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/testlib/testlib.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Test Subprocess Helper Macros
*
* These macros may be used to run unit tests in a subprocess. It's
* particularly useful when testing code that causes the process to die:
*
* TEST(term, test) {
* SPAWN(fork);
* raise(SIGUSR1);
* TERMS(SIGUSR1);
* }
*
* The default action for both EXITS() and TERMS() is _Exit(0), unless
* an EXPECT_FOO() macro failed, in which case the status is non-zero.
*
* TEST(my, test) {
* SPAWN(fork);
* // do stuff
* EXITS(0);
* }
*
* You can also nest subprocesses:
*
* TEST(exit, test) {
* SPAWN(fork);
* SPAWN(vfork);
* _Exit(2);
* EXITS(2);
* _Exit(1);
* EXITS(1);
* }
*
* The above are shorthand for:
*
* TEST(my, test) {
* SPAWN(fork);
* // communicate with parent
* PARENT();
* // communicate with child
* WAIT(exit, 0)
* }
*
* These macros cause a local variable named `child` with the child pid
* to be defined.
*/
#define SPAWN(METHOD) \
{ \
int child, _failed = g_testlib_failed; \
ASSERT_NE(-1, (child = METHOD())); \
if (!child) {
#define EXITS(CODE) \
PARENT() \
WAIT(exit, CODE)
#define TERMS(SIG) \
PARENT() \
WAIT(term, SIG)
#define PARENT() \
_Exit(MAX(0, MIN(255, g_testlib_failed - _failed))); \
}
#define WAIT(KIND, CODE) \
testlib_waitfor##KIND(__FILE__, __LINE__, #CODE, CODE, child); \
}
void testlib_waitforexit(const char *, int, const char *, int, int);
void testlib_waitforterm(const char *, int, const char *, int, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_TESTLIB_SUBPROCESS_H_ */