423 lines
11 KiB
C++
423 lines
11 KiB
C++
|
//This file is part of the reprodyne project and is licensed under the terms of the LGPL-3.0-only
|
||
|
|
||
|
|
||
|
#include <catch2/catch.hpp>
|
||
|
|
||
|
#include "../user-include/reprodyne.h"
|
||
|
|
||
|
#include "oopsiewhoopsie.h"
|
||
|
|
||
|
const auto testDataPath = "reprodyne-test-data.rep";
|
||
|
|
||
|
|
||
|
void code_gobbling_error_handler(const int code, const char*)
|
||
|
{
|
||
|
throw OopsieWhoopsie(code);
|
||
|
}
|
||
|
|
||
|
std::vector<double> generateList()
|
||
|
{
|
||
|
//Tried this in a lambda but gcc is too clever for it's own good.
|
||
|
return std::initializer_list<double>({time(), time(), time(), time()});
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Big ugly test group")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
int scope1; //Only used for their addresses
|
||
|
int scope2;
|
||
|
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
|
||
|
auto interceptHelper = [&](void* scope, std::string key, auto list, std::vector<double> validationSet)
|
||
|
{
|
||
|
for(int i = 0; i != list.size(); ++i)
|
||
|
{
|
||
|
const double rep = reprodyne_intercept_double(scope, key.c_str(), list[i]);
|
||
|
|
||
|
if(validationSet.size()) REQUIRE(validationSet[i] == rep);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
auto callHelper = [&](void* scope, std::string key, auto list)
|
||
|
{
|
||
|
for(const double i : list)
|
||
|
reprodyne_validate_string(scope, key.c_str(), std::string("pretendFunctionCall(" + std::to_string(i) + ");").c_str());
|
||
|
};
|
||
|
|
||
|
|
||
|
const auto originalSetScope1 = generateList();
|
||
|
const auto originalSetScope2 = generateList();
|
||
|
|
||
|
//Consequently, this tests that the original values are returned
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, originalSetScope1);
|
||
|
reprodyne_mark_frame();
|
||
|
interceptHelper(&scope2, "the-wan", originalSetScope2, originalSetScope2);
|
||
|
callHelper(&scope2, "the-wan", originalSetScope2);
|
||
|
|
||
|
{
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath); //Automatically re-initializes everything, don't worry~
|
||
|
|
||
|
reprodyne_set_playback_failure_handler(&code_gobbling_error_handler);
|
||
|
|
||
|
reprodyne_mark_frame();
|
||
|
}
|
||
|
SECTION("Correct interception")
|
||
|
{
|
||
|
int rescope2;
|
||
|
int rescope1;
|
||
|
|
||
|
reprodyne_open_scope(&rescope1);
|
||
|
reprodyne_open_scope(&rescope2);
|
||
|
|
||
|
SECTION("Discard supplied indeterminates, returning originals")
|
||
|
{
|
||
|
//These new values are intercepted and replaced
|
||
|
const auto secondSetScope1 = generateList();
|
||
|
const auto secondSetScope2 = generateList();
|
||
|
|
||
|
interceptHelper(&rescope1, "the-wan", secondSetScope1, originalSetScope1);
|
||
|
reprodyne_mark_frame();
|
||
|
interceptHelper(&rescope2, "the-wan", secondSetScope2, originalSetScope2);
|
||
|
callHelper(&rescope2, "the-wan", originalSetScope2);
|
||
|
|
||
|
reprodyne_assert_complete_read();
|
||
|
}
|
||
|
}
|
||
|
SECTION("Mismatched frame")
|
||
|
{
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
|
||
|
/*MARK FRAME MISSING*/
|
||
|
|
||
|
try
|
||
|
{
|
||
|
interceptHelper(&scope2, "the-wan", originalSetScope2, {});
|
||
|
FAIL("Intercept didn't fail with mismatched frame calls");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_FRAME_MISMATCH);
|
||
|
SUCCEED();
|
||
|
}
|
||
|
}
|
||
|
SECTION("Read past the end")
|
||
|
{
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
|
||
|
try
|
||
|
{
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
FAIL("Read past end didn't fail correctly");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_TAPE_PAST_END);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Call mismatch")
|
||
|
{
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
reprodyne_mark_frame();
|
||
|
interceptHelper(&scope2, "the-wan", originalSetScope2, {});
|
||
|
|
||
|
try
|
||
|
{
|
||
|
reprodyne_validate_string(&scope2, "the-wan", "wrongo");
|
||
|
FAIL("Mismatched Call not detected.");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
//Check da oophs code
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_VALIDATION_FAIL);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Incomplete program read")
|
||
|
{
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
reprodyne_assert_complete_read();
|
||
|
FAIL("Reprodyne should have aborted on incomplete program read.");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_PROG_TAPE_INCOMPLETE_READ);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Incomplete call read")
|
||
|
{
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope2);
|
||
|
|
||
|
interceptHelper(&scope1, "the-wan", originalSetScope1, {});
|
||
|
reprodyne_mark_frame();
|
||
|
interceptHelper(&scope2, "the-wan", originalSetScope2, {});
|
||
|
|
||
|
/*SERIALIZE CALL MISSING*/
|
||
|
|
||
|
try
|
||
|
{
|
||
|
reprodyne_assert_complete_read();
|
||
|
FAIL("Reprodyne should have aborted on incomplete call read.");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_CALL_TAPE_INCOMPLETE_READ);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Scope override")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
int scope;
|
||
|
|
||
|
reprodyne_open_scope(&scope);
|
||
|
reprodyne_intercept_double(&scope, "n", 42);
|
||
|
|
||
|
reprodyne_open_scope(&scope);
|
||
|
reprodyne_intercept_double(&scope, "n", 240); //Dyslexics be blazin' like
|
||
|
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
auto validate = [](void* scope1, void* scope2)
|
||
|
{
|
||
|
reprodyne_open_scope(scope1);
|
||
|
REQUIRE(reprodyne_intercept_double(scope1, "n", 4839) == 42);
|
||
|
|
||
|
reprodyne_open_scope(scope2);
|
||
|
REQUIRE(reprodyne_intercept_double(scope2, "n", 43894389) == 240);
|
||
|
|
||
|
SECTION("Assert complete read for overriden scope")
|
||
|
{
|
||
|
reprodyne_assert_complete_read();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
SECTION("Playback override with one pointer")
|
||
|
{
|
||
|
int scopee;
|
||
|
validate(&scopee, &scopee);
|
||
|
}
|
||
|
SECTION("Playback override with two pointers")
|
||
|
{
|
||
|
int scope1;
|
||
|
int scope2;
|
||
|
validate(&scope1, &scope2);
|
||
|
}
|
||
|
|
||
|
SECTION("Assert complete read after clobbering incompletely read scope")
|
||
|
{
|
||
|
int scope1;
|
||
|
|
||
|
reprodyne_open_scope(&scope1);
|
||
|
reprodyne_open_scope(&scope1); //CLOBBER
|
||
|
|
||
|
REQUIRE(reprodyne_intercept_double(&scope1, "n", 43894389) == 240);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
reprodyne_assert_complete_read();
|
||
|
FAIL("Reprodyne should have aborted on incomplete indeterminate read.");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_PROG_TAPE_INCOMPLETE_READ);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Invalid scope key")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
int scope;
|
||
|
reprodyne_open_scope(&scope);
|
||
|
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
|
||
|
//TODO: make a test for this without these two lines? Whatever condition that is... Too busy to think r/n
|
||
|
reprodyne_mark_frame();
|
||
|
reprodyne_open_scope(&scope);
|
||
|
|
||
|
reprodyne_set_playback_failure_handler(&code_gobbling_error_handler);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
reprodyne_intercept_double(&scope, "notta", 42);
|
||
|
FAIL("Intercept with bad key in playback mode didn't fail");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_EMPTY_TAPE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Validation and program tape different sizes, larger program tape")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
double up;
|
||
|
reprodyne_open_scope(&up);
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
reprodyne_mark_frame();
|
||
|
reprodyne_open_scope(&up);
|
||
|
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
|
||
|
reprodyne_assert_complete_read();
|
||
|
|
||
|
SUCCEED("If we made it this far it worked");
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Validation and program tape different sizes, larger validation tape")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
double up;
|
||
|
reprodyne_open_scope(&up);
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
reprodyne_mark_frame();
|
||
|
reprodyne_open_scope(&up);
|
||
|
|
||
|
reprodyne_intercept_double(&up, "key", 42);
|
||
|
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
reprodyne_validate_string(&up, "ee", "ffff");
|
||
|
|
||
|
reprodyne_assert_complete_read();
|
||
|
|
||
|
SUCCEED("If we made it this far it worked");
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Graceful handling of saved file with no entries")
|
||
|
{
|
||
|
reprodyne_record();
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
reprodyne_set_playback_failure_handler(&code_gobbling_error_handler);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
double up;
|
||
|
reprodyne_mark_frame();
|
||
|
reprodyne_intercept_double(&up, "fdsfd", 34243);
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
//This is really all we can get to I think...
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_UNREGISTERED_SCOPE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST_CASE("Unregistered scope")
|
||
|
{
|
||
|
int s;
|
||
|
reprodyne_record();
|
||
|
reprodyne_mark_frame();
|
||
|
reprodyne_open_scope(&s);
|
||
|
|
||
|
reprodyne_set_playback_failure_handler(&code_gobbling_error_handler);
|
||
|
|
||
|
double up;
|
||
|
|
||
|
SECTION("Write indeterminate with bad scope")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reprodyne_intercept_double(&up, "fj", 43);
|
||
|
FAIL("Unregistered scope accepted in indeterminate write");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_UNREGISTERED_SCOPE);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Serialize with bad scope")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reprodyne_validate_string(&up, "fjfjfjasdfdas", "CEREAL");
|
||
|
FAIL("Unregistered scope accepted in serialize write");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_UNREGISTERED_SCOPE);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Reads")
|
||
|
{
|
||
|
reprodyne_save(testDataPath);
|
||
|
reprodyne_play(testDataPath);
|
||
|
reprodyne_mark_frame();
|
||
|
|
||
|
SECTION("Read indeterminate with bad scope")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reprodyne_intercept_double(&up, "bep", 3);
|
||
|
FAIL("Unregistered scope accepted in indeterminate read");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_UNREGISTERED_SCOPE);
|
||
|
}
|
||
|
}
|
||
|
SECTION("Read stored call with bad scope")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
reprodyne_validate_string(&up, "bep", "");
|
||
|
FAIL("Unregistered scope accepted for serialize read");
|
||
|
}
|
||
|
catch(const OopsieWhoopsie& oops)
|
||
|
{
|
||
|
REQUIRE(oops.code == REPRODYNE_STAT_UNREGISTERED_SCOPE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|