silentbicycle / theft

property-based testing for C: generate input to find obscure bugs, then reduce to minimal failing input
ISC License
611 stars 31 forks source link

Composability of hook environments #17

Open silentbicycle opened 7 years ago

silentbicycle commented 7 years ago

Sharing the hook environment between mutually unaware hooks is awkward -- if the environment is cast to a particular struct pointer, all hooks need to account for the type, and it may need to box the environments for built-in hooks such as theft_hook_trial_post_print_result.

The heart of the problem is a lack of late binding -- without breaking reverse compatibility, theft could provide an optional, dynamically allocated environment, with some sort of magic tag to check before casting: the user could construct a key/value environment with defaults, and hook-specific state could be keyed by name:

struct theft_env *hook_env = theft_env_defaults(t);

Built-in hooks would have reserved keys.

The environment could tag the value with a general type internally, and have type-specific get/set functions. (Maybe just void * and int.)

theft_env_bind_int(hook_env, "VERBOSITY", 1);
uint8_t verbosity = (uint8_t)theft_env_get_int(hook_env, "VERBOSITY");

theft_env_bind_ptr(hook_env, "CUSTOM_HOOK_INFO", &info); 
void *info = theft_env_get_ptr(hook_env, "CUSTOM_HOOK_INFO");

theft_env_new(t); could construct an environment without any defaults (for other cases where a dynamic environment is useful).

This environment would have the same lifetime as the theft-instance, so (if used) it could be freed inside theft_run_free, or theft_env_free(t, hook_env); could be used explicitly.

The environment could be implemented with a relatively simple (const char * -> tagged(int | void *)) map type.