From 6dc8bf73292d6a5ff4b1312716648f2f5ce90a6c Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sun, 18 May 2014 10:10:04 -0400 Subject: [PATCH] random: Use a different RNG for testing This RNG is more predictable, which makes it great for testing. Signed-off-by: Anna Schumaker --- DESIGN | 20 ++++++++++++++++++++ include/random.h | 36 ++++++++++++++++++++++++++++++++++++ lib/random.cpp | 21 +++++++++++++++++++++ tests/.gitignore | 1 + tests/Sconscript | 1 + tests/random.cpp | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 include/random.h create mode 100644 lib/random.cpp create mode 100644 tests/random.cpp diff --git a/DESIGN b/DESIGN index e329d720..630b4cba 100644 --- a/DESIGN +++ b/DESIGN @@ -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: Queues are lists of songs that the user has requested to play. They are the main interface for all music played by Ocarina. diff --git a/include/random.h b/include/random.h new file mode 100644 index 00000000..5627ea2f --- /dev/null +++ b/include/random.h @@ -0,0 +1,36 @@ +/* + * Copyright 2014 (c) Anna Schumaker + */ + +#ifndef OCARINA_RANDOM_H +#define OCARINA_RANDOM_H + +#ifndef CONFIG_TEST + +#include +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 */ diff --git a/lib/random.cpp b/lib/random.cpp new file mode 100644 index 00000000..3488e277 --- /dev/null +++ b/lib/random.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2014 (c) Anna Schumaker + */ +#ifdef CONFIG_TEST + +#include + +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 */ diff --git a/tests/.gitignore b/tests/.gitignore index e51c1ed3..8bb107e7 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,4 +5,5 @@ index filter idle tags +random queue diff --git a/tests/Sconscript b/tests/Sconscript index 39ba2253..fa3d25e8 100644 --- a/tests/Sconscript +++ b/tests/Sconscript @@ -16,6 +16,7 @@ tests = [ ("filter.cpp", True, [], []), ("idle.cpp", False, [ "idle.cpp" ], []), ("tags.cpp", True, [], [ "taglib" ]), + ("random.cpp", False, [ "random.cpp" ], []), ("queue.cpp", True, [ "callback.cpp" ], []), ] diff --git a/tests/random.cpp b/tests/random.cpp new file mode 100644 index 00000000..1d714404 --- /dev/null +++ b/tests/random.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2014 (c) Anna Schumaker. + */ + +#include +#include "test.h" + +#include + +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; +}