random: Use a different RNG for testing

This RNG is more predictable, which makes it great for testing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2014-05-18 10:10:04 -04:00
parent 7aa5f22777
commit 6dc8bf7329
6 changed files with 115 additions and 0 deletions

20
DESIGN
View File

@ -828,6 +828,26 @@ Track Tag:
Random:
The random number generator is used by the Queue to pick a song as
randomly as possible. I use two different RNG implementations,
depending on if Ocarina is compiled with CONFIG_TEST or not.
When CONFIG_TEST is enabled, the RNG is a simple counter. Every time
_pick_random() is called, the counter is incremented and returned.
When compiled without CONFIG_TEST we will return values using the
rand() function from stdlib.h.
- API:
void random_seed(unsigned int n);
Seed the random number generator based on n.
void random(unsigned int min, unsigned int max);
Return a random number between min and max, inclusive.
If min >= max: return min.
Queue: Queue:
Queues are lists of songs that the user has requested to play. They Queues are lists of songs that the user has requested to play. They
are the main interface for all music played by Ocarina. are the main interface for all music played by Ocarina.

36
include/random.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright 2014 (c) Anna Schumaker
*/
#ifndef OCARINA_RANDOM_H
#define OCARINA_RANDOM_H
#ifndef CONFIG_TEST
#include <stdlib.h>
static inline void _seed_random(unsigned int n) { srand(time(NULL) + n); }
static inline unsigned int _pick_random() { return rand(); }
#else /* CONFIG_TEST */
void _seed_random(unsigned int);
unsigned int _pick_random();
#endif /* CONFIG_TEST */
static inline void random_seed(unsigned int n)
{
_seed_random(n);
}
static inline unsigned int random(unsigned int min, unsigned int max)
{
if (min >= max)
return min;
return min + (_pick_random() % (max - min));
}
#endif /* OCARINA_RANDOM_H */

21
lib/random.cpp Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright 2014 (c) Anna Schumaker
*/
#ifdef CONFIG_TEST
#include <random.h>
static unsigned int _random_value = 0;
void _seed_random(unsigned int n)
{
_random_value = n;
}
unsigned int _pick_random()
{
return ++_random_value;
}
#endif /* CONFIG_TEST */

1
tests/.gitignore vendored
View File

@ -5,4 +5,5 @@ index
filter filter
idle idle
tags tags
random
queue queue

View File

@ -16,6 +16,7 @@ tests = [
("filter.cpp", True, [], []), ("filter.cpp", True, [], []),
("idle.cpp", False, [ "idle.cpp" ], []), ("idle.cpp", False, [ "idle.cpp" ], []),
("tags.cpp", True, [], [ "taglib" ]), ("tags.cpp", True, [], [ "taglib" ]),
("random.cpp", False, [ "random.cpp" ], []),
("queue.cpp", True, [ "callback.cpp" ], []), ("queue.cpp", True, [ "callback.cpp" ], []),
] ]

36
tests/random.cpp Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <random.h>
#include "test.h"
#include <sstream>
static void do_test_rng(unsigned int seed)
{
random_seed(seed);
for (unsigned int i = 0; i <= 10; i++) {
if (i <= seed)
test_equal(random(seed, i), seed);
else
test_equal(random(seed, i), seed + (i % (i - seed)));
}
}
static void test_rng(unsigned int seed)
{
std::stringstream ss;
ss << " (seed = " << seed << ")";
std::string seed_str = ss.str();
run_test("Random Number Generator Test" + seed_str, do_test_rng, seed);
}
int main(int argc, char **argv)
{
for (unsigned int i = 0; i < 10; i++)
test_rng(i);
return 0;
}