static void test_callbackCalledWithChangeDetection (void)
{
	printf ("test callback is not called when key has not changed\n");

	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("internalnotification");

	char * value = "foobaroo!";
	Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_VALUE, value, KEY_END);
	KeySet * ks = ksNew (1, valueKey, KS_END);

	succeed_if (internalnotificationRegisterCallback (plugin, valueKey, test_callback) == 1,
		    "call to elektraInternalnotificationRegisterCallback was not successful");

	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);

	succeed_if (callback_called, "registered value was not updated");

	callback_called = 0;
	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);
	succeed_if (callback_called == 0, "registered value was updated but value has not changed");

	ksDel (ks);
	PLUGIN_CLOSE ();
}
static void test_intNoUpdateWithValueExceedingIntMin (void)
{
	printf ("test no update with value that exceeds INT_MIN\n");

	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("internalnotification");

	Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_END);
	KeySet * ks = ksNew (1, valueKey, KS_END);

	int value = 123;
	succeed_if (internalnotificationRegisterInt (plugin, valueKey, &value) == 1,
		    "call to elektraInternalnotificationRegisterInt was not successful");

	long long exceedsInt = (long long) INT_MIN - 1;
	char * stringValue = convertLongLongToString (exceedsInt);
	keySetString (valueKey, stringValue);

	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);

	succeed_if (value == 123, "registered value was updated");

	elektraFree (stringValue);
	ksDel (ks);
	PLUGIN_CLOSE ();
}
/**
 * Updates registrations with current data from storage.
 * Part of elektra plugin contract.
 *
 * @param  handle    plugin handle
 * @param  returned  key set containing current data from storage
 * @param  parentKey key for errors
 *
 * @retval 1 on success
 * @retval -1 on failure
 */
int elektraInternalnotificationGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/internalnotification"))
	{
		KeySet * contract = ksNew (
			30,
			keyNew ("system/elektra/modules/internalnotification", KEY_VALUE,
				"internalnotification plugin waits for your orders", KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports", KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/get", KEY_FUNC, elektraInternalnotificationGet,
				KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/set", KEY_FUNC, elektraInternalnotificationSet,
				KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/open", KEY_FUNC, elektraInternalnotificationOpen,
				KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/close", KEY_FUNC, elektraInternalnotificationClose,
				KEY_END),

			keyNew ("system/elektra/modules/internalnotification/exports/notificationCallback", KEY_FUNC,
				elektraInternalnotificationDoUpdate, KEY_END),

			// Export register* functions
			INTERNALNOTIFICATION_EXPORT_FUNCTION (Int), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedInt),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (Long), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedLong),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (LongLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (UnsignedLongLong),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (Float), INTERNALNOTIFICATION_EXPORT_FUNCTION (Double),

			// Export register* functions for kdb_*_t types
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbBoolean), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbChar),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbOctet), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbShort),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedShort), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLong),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLongLong),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbUnsignedLongLong), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbFloat),
			INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbDouble), INTERNALNOTIFICATION_EXPORT_FUNCTION (KdbLongDouble),

			keyNew ("system/elektra/modules/internalnotification/exports/registerCallback", KEY_FUNC,
				elektraInternalnotificationRegisterCallback, KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/registerCallbackSameOrBelow", KEY_FUNC,
				elektraInternalnotificationRegisterCallbackSameOrBelow, KEY_END),
			keyNew ("system/elektra/modules/internalnotification/exports/setConversionErrorCallback", KEY_FUNC,
				elektraInternalnotificationSetConversionErrorCallback, KEY_END),

#include ELEKTRA_README

			keyNew ("system/elektra/modules/internalnotification/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, contract);
		ksDel (contract);

		return 1;
	}

	elektraInternalnotificationUpdateRegisteredKeys (handle, returned);

	return 1;
}
static void test_callbackCalledWithKey (void)
{
	printf ("test callback is called with changed key\n");

	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("internalnotification");

	char * value = "foobaroo!";
	Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_VALUE, value, KEY_END);
	KeySet * ks = ksNew (1, valueKey, KS_END);

	succeed_if (internalnotificationRegisterCallback (plugin, valueKey, test_callback) == 1,
		    "call to elektraInternalnotificationRegisterCallback was not successful");

	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);

	succeed_if (callback_called, "registered value was not updated");
	succeed_if_same_string (callback_keyName, keyName (valueKey));
	succeed_if_same_string (callback_keyValue, value);

	ksDel (ks);
	PLUGIN_CLOSE ();
}
static void test_intUpdateWithCascadingKey (void)
{
	printf ("test update with cascading key registered\n");

	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("internalnotification");

	Key * registeredKey = keyNew ("/test/internalnotification/value", KEY_END);
	int value = 0;
	succeed_if (internalnotificationRegisterInt (plugin, registeredKey, &value) == 1,
		    "call to elektraInternalnotificationRegisterInt was not successful");

	Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_VALUE, "42", KEY_END);
	KeySet * ks = ksNew (1, valueKey, KS_END);

	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);

	succeed_if (value == 42, "registered value was not updated");

	keyDel (registeredKey);
	ksDel (ks);
	PLUGIN_CLOSE ();
}
static void test_intNoUpdateWithInvalidValue (void)
{
	printf ("test no update with invalid value\n");

	KeySet * conf = ksNew (0, KS_END);
	PLUGIN_OPEN ("internalnotification");

	Key * valueKey = keyNew ("user/test/internalnotification/value", KEY_END);
	KeySet * ks = ksNew (1, valueKey, KS_END);

	int value = 123;
	succeed_if (internalnotificationRegisterInt (plugin, valueKey, &value) == 1,
		    "call to elektraInternalnotificationRegisterInt was not successful");

	keySetString (valueKey, "42abcd");


	elektraInternalnotificationUpdateRegisteredKeys (plugin, ks);

	succeed_if (value == 123, "registered value was updated");

	ksDel (ks);
	PLUGIN_CLOSE ();
}