Command line test runner
fprintf(stderr, "Unable to read program output\n"); loses important information: exactly why the program output couldn't be read. Prefer perror.

Ditto for other fprintf(stderr, ....).
The parent doesn't wait for children. You may produce plenty of zombies.
The parent doesn't close(stdout_pipe[0]); when done with a child. You may run out of file descriptors.
The spec file format seems naive:


There is no way to deal with a multi-line output.
It mixes child's stdout and stderr. If the child produces both, their order is unpredictable.
It doesn't specify the child's return status.