aboutsummaryrefslogtreecommitdiff
path: root/tests/README.md
diff options
context:
space:
mode:
authorCole Lightfighter <cole@onicsla.bz>2017-09-19 15:09:38 -0600
committerCole Lightfighter <cole@onicsla.bz>2017-09-19 15:09:38 -0600
commitc300ae56ca79051b7178c7d689c13b5207d92702 (patch)
tree6a33aa9493a149dbb0a07f351debb0173557b57f /tests/README.md
parentAdded test documentation & Keccak unit test (diff)
downloadmonero-c300ae56ca79051b7178c7d689c13b5207d92702.tar.xz
Added test documentation & Keccak unit test
Diffstat (limited to 'tests/README.md')
-rw-r--r--tests/README.md178
1 files changed, 178 insertions, 0 deletions
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 000000000..b76d3507d
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,178 @@
+# Crypto tests
+
+## Running crypto Perl tests
+
+Crypto tests require the Math::GMP Perl library, make sure it is installed on you system before running the tests.
+
+Installing dependencies (using cpan):
+
+```
+cpan
+cpan> install Math::BigInt::GMP
+cpan> install Digest::Keccak
+```
+
+Running tests:
+
+```
+TESTPATH=/path/to/monero/tests
+cd $TESTPATH
+perl -I $TESTPATH cryptotest.pl
+```
+
+Important: must include test path for perl to import cryptolib.pl
+
+## Writing new crypto tests
+
+[TODO]
+
+# Core tests
+
+## Running core tests
+
+Monero uses the Google C++ Testing Framework (`gtest`) to write unit, integration and functional tests for core and other features of the project.
+`gtest` runs on top of cmake, and you can run all tests by:
+
+```
+cd /path/to/monero
+make [-jn] debug-test # where n is number of compiler processes
+```
+
+To test a release build, replace `debug-test` with `release-test` in the previous command.
+
+One can also run individual test suites by building monero, then running `ctest` in test suite folders.
+
+Run only the hash tests:
+
+```
+cd /path/to/monero
+make [-j#] debug
+cd build/debug/tests/hash
+ctest
+```
+
+To run the same tests on a release build, replace `debug` with `release` in previous commands.
+
+## Writing new tests
+
+Based on local tests and Google's guide on creating [simple tests with gtest](https://github.com/google/googletest/blob/master/googletest/docs/Primer.md#simple-tests)
+
+Tests consist of a test harness (defined with the TEST() macro), and the test body consisting of gtest assertions.
+
+Example of a test harness:
+
+```
+TEST(test_case_name, test_name) {
+ ... test body ...
+
+}
+```
+
+As an example in Monero's [crypto unit test](./unit_tests/crypto.cpp):
+
+```
+TEST(Crypto, Ostream)
+{
+ EXPECT_TRUE(is_formatted<crypto::hash8>());
+ EXPECT_TRUE(is_formatted<crypto::hash>());
+ EXPECT_TRUE(is_formatted<crypto::public_key>());
+ EXPECT_TRUE(is_formatted<crypto::secret_key>());
+ EXPECT_TRUE(is_formatted<crypto::signature>());
+ EXPECT_TRUE(is_formatted<crypto::key_derivation>());
+ EXPECT_TRUE(is_formatted<crypto::key_image>());
+}
+
+```
+
+The assertions inside the test harness are a bit complex, but fairly straightforward.
+
+- `is_formatted<T>()` is a polymorphic function that accepts the various types of structs defined in [crypto/hash.h](../src/crypto/hash.h).
+
+Just above the test harness, we have the definition for `is_formatted`:
+
+```
+ template<typename T>
+ bool is_formatted()
+ {
+ T value{};
+
+ static_assert(alignof(T) == 1, "T must have 1 byte alignment");
+ static_assert(sizeof(T) <= sizeof(source), "T is too large for source");
+ static_assert(sizeof(T) * 2 <= sizeof(expected), "T is too large for destination");
+ std::memcpy(std::addressof(value), source, sizeof(T));
+
+ std::stringstream out;
+ out << "BEGIN" << value << "END";
+ return out.str() == "BEGIN<" + std::string{expected, sizeof(T) * 2} + ">END";
+ }
+```
+
+`T value {}` produces the data member of the struct (`hash8` has `char data[8]`), which runs a number of tests to ensure well structured hash data.
+
+Let's write a new test for the keccak function:
+
+```
+ bool keccak_harness()
+ {
+ size_t inlen = sizeof(source);
+ int mdlen = (int)sizeof(md);
+ int ret = keccak(source, inlen, md, mdlen);
+ if (md[0] != 0x00)
+ {
+ return true;
+ }
+ else if (!ret)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+```
+
+This is a basic test that ensures `keccak()` returns successfully when given proper input. It reuses the `source` array for input, and a new byte array `md` for storing the hash digest. Full source is in the [crypto unit test](./unit_tests/crypto.cpp).
+
+Now let's create a new test harness:
+
+```
+TEST(Crypto, Keccak)
+{
+ # ...
+ EXPECT_TRUE(keccak_harness());
+}
+
+```
+
+This creates a new test under the `Crypto` test case named `Keccak`. The harness includes one assertion `EXPECT_TRUE(keccak_harness())`, which invokes `keccak_harness()`. More complex logic can be added to test various functionality of the `Keccak` library.
+
+To run the new test:
+
+```
+cd /path/to/monero
+make -jn debug # if no debug build exists
+cd build/debug/tests/unit_test
+make -jn
+make -jn test
+```
+
+# Fuzz tests
+
+## Running fuzz tests
+
+```
+cd /path/to/monero
+make [-jn] fuzz # where n is number of compiler processes
+```
+
+or
+
+```
+cd path/to/monero
+./contrib/fuzz_testing/fuzz.sh
+```
+
+## Writing fuzz tests
+
+[TODO]