bool TestOS_RNG()
{
	bool pass = true;

	member_ptr<RandomNumberGenerator> rng;

#ifdef BLOCKING_RNG_AVAILABLE
	try {rng.reset(new BlockingRng);}
	catch (const OS_RNG_Err &) {}
#endif

	if (rng.get())
	{
		std::cout << "\nTesting operating system provided blocking random number generator...\n\n";

		MeterFilter meter(new Redirector(TheBitBucket()));
		RandomNumberSource test(*rng, UINT_MAX, false, new Deflator(new Redirector(meter)));
		unsigned long total=0, length=0;
		time_t t = time(NULLPTR), t1 = 0;
		CRYPTOPP_UNUSED(length);

		// check that it doesn't take too long to generate a reasonable amount of randomness
		while (total < 16 && (t1 < 10 || total*8 > (unsigned long)t1))
		{
			test.Pump(1);
			total += 1;
			t1 = time(NULLPTR) - t;
		}

		if (total < 16)
		{
			std::cout << "FAILED:";
			pass = false;
		}
		else
			std::cout << "passed:";
		std::cout << "  it took " << long(t1) << " seconds to generate " << total << " bytes" << std::endl;

#if 0	// disable this part. it's causing an unpredictable pause during the validation testing
		if (t1 < 2)
		{
			// that was fast, are we really blocking?
			// first exhaust the extropy reserve
			t = time(NULLPTR);
			while (time(NULLPTR) - t < 2)
			{
				test.Pump(1);
				total += 1;
			}

			// if it generates too many bytes in a certain amount of time,
			// something's probably wrong
			t = time(NULLPTR);
			while (time(NULLPTR) - t < 2)
			{
				test.Pump(1);
				total += 1;
				length += 1;
			}
			if (length > 1024)
			{
				std::cout << "FAILED:";
				pass = false;
			}
			else
				std::cout << "passed:";
			std::cout << "  it generated " << length << " bytes in " << long(time(NULLPTR) - t) << " seconds" << std::endl;
		}
#endif

		test.AttachedTransformation()->MessageEnd();

		if (meter.GetTotalBytes() < total)
		{
			std::cout << "FAILED:";
			pass = false;
		}
		else
			std::cout << "passed:";
		std::cout << "  " << total << " generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";

		try
		{
			// Miscellaneous for code coverage
			RandomNumberGenerator& prng = *rng.get();
			(void)prng.AlgorithmName();
			word32 result = prng.GenerateWord32();
			result = prng.GenerateWord32((result & 0xff), 0xffffffff - (result & 0xff));
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 4);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 3);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 2);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 1);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 0);
			pass = true;
		}
		catch (const Exception&)
		{
			pass = false;
		}

		if (!pass)
			std::cout << "FAILED:";
		else
			std::cout << "passed:";
		std::cout << "  GenerateWord32 and Crop\n";
	}
	else
		std::cout << "\nNo operating system provided blocking random number generator, skipping test." << std::endl;

	rng.reset(NULLPTR);
#ifdef NONBLOCKING_RNG_AVAILABLE
	try {rng.reset(new NonblockingRng);}
	catch (OS_RNG_Err &) {}
#endif

	if (rng.get())
	{
		std::cout << "\nTesting operating system provided nonblocking random number generator...\n\n";

		MeterFilter meter(new Redirector(TheBitBucket()));
		RandomNumberSource test(*rng, 100000, true, new Deflator(new Redirector(meter)));

		if (meter.GetTotalBytes() < 100000)
		{
			std::cout << "FAILED:";
			pass = false;
		}
		else
			std::cout << "passed:";
		std::cout << "  100000 generated bytes compressed to " << meter.GetTotalBytes() << " bytes by DEFLATE\n";

		try
		{
			// Miscellaneous for code coverage
			RandomNumberGenerator& prng = *rng.get();
			(void)prng.AlgorithmName();
			word32 result = prng.GenerateWord32();
			result = prng.GenerateWord32((result & 0xff), 0xffffffff - (result & 0xff));
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 4);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 3);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 2);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 1);
			prng.GenerateBlock(reinterpret_cast<byte*>(&result), 0);
			pass = true;
		}
		catch (const Exception&)
		{
			pass = false;
		}

		if (!pass)
			std::cout << "FAILED:";
		else
			std::cout << "passed:";
		std::cout << "  GenerateWord32 and Crop\n";
	}
	else
		std::cout << "\nNo operating system provided nonblocking random number generator, skipping test." << std::endl;

	return pass;
}