mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-05 23:48:31 -04:00
39fea200ca
Now a variable belonging to a group can safely be constructed before the group it belongs to, and the group can be destroyed before its member variables. This greatly simplifies the AP_Var constructor(s). Remove the lookup-by-index and lookup-by-key interfaces to AP_Var and replace them with first/next interfaces for all variables, and for variables belonging to a specific group. Document their usage. Add an accessor for the key associated with a variable so that search-by-key can be performed by a consumer. Throw away the lookup cache implementation, as it's not required anymore. Re-layout the EEPROM variable header and tweak the EEPROM space allocator so that it's more resistant to interruptions during variable save. Fix the global constants so that they work. Add an interface for erasing all variables in EEPROM (only writes one byte). Fix unit tests so that they work with the changed interfaces. Also tweak the unit test framework so that it doesn't inline all its code. This is a WIP - many more tests need to be written still. git-svn-id: https://arducopter.googlecode.com/svn/trunk@1531 f9c3cf11-9bcb-44bc-f272-b75c42450872
372 lines
7.6 KiB
Plaintext
372 lines
7.6 KiB
Plaintext
//
|
|
// Unit tests for the AP_Meta_class and AP_Var classes.
|
|
//
|
|
|
|
#include <FastSerial.h>
|
|
#include <AP_Common.h>
|
|
#include <string.h>
|
|
|
|
// we need to do this, even though normally it's a bad idea
|
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
|
|
|
FastSerialPort(Serial, 0);
|
|
|
|
//
|
|
// Unit test framework
|
|
//
|
|
class Test
|
|
{
|
|
public:
|
|
Test(const char *name);
|
|
~Test();
|
|
void require(bool expr, const char *source);
|
|
static void report();
|
|
|
|
private:
|
|
const char *_name;
|
|
bool _fail;
|
|
static int _passed;
|
|
static int _failed;
|
|
};
|
|
|
|
Test::Test(const char *name) :
|
|
_name(name),
|
|
_fail(false)
|
|
{
|
|
}
|
|
|
|
Test::~Test()
|
|
{
|
|
Serial.printf("%s: %s\n", _fail ? "FAILED" : "passed", _name);
|
|
if (_fail) {
|
|
_failed++;
|
|
} else {
|
|
_passed++;
|
|
}
|
|
}
|
|
|
|
void
|
|
Test::require(bool expr, const char *source)
|
|
{
|
|
if (!expr) {
|
|
_fail = true;
|
|
Serial.printf("%s: fail: %s\n", _name, source);
|
|
}
|
|
}
|
|
|
|
void
|
|
Test::report()
|
|
{
|
|
Serial.printf("\n%d passed %d failed\n", _passed, _failed);
|
|
}
|
|
|
|
int Test::_passed = 0;
|
|
int Test::_failed = 0;
|
|
|
|
#define TEST(name) Test _test(#name)
|
|
#define REQUIRE(expr) _test.require(expr, #expr)
|
|
|
|
//
|
|
// Unit tests
|
|
//
|
|
void
|
|
setup(void)
|
|
{
|
|
Serial.begin(115200);
|
|
Serial.println("AP_Var unit tests.\n");
|
|
|
|
// MetaClass: test type ID
|
|
{
|
|
TEST(meta_type_id);
|
|
|
|
AP_Float f1(0);
|
|
AP_Float f2(0);
|
|
AP_Int8 i1(0);
|
|
|
|
uint16_t m1 = f1.meta_type_id();
|
|
uint16_t m2 = f2.meta_type_id();
|
|
uint16_t m3 = i1.meta_type_id();
|
|
uint16_t m4 = AP_Meta_class::meta_type_id<AP_Float>();
|
|
|
|
REQUIRE(m1 != 0);
|
|
REQUIRE(m1 == m2);
|
|
REQUIRE(m1 != m3);
|
|
REQUIRE(m1 == m4);
|
|
}
|
|
|
|
// MetaClass: meta_type_equivalent
|
|
{
|
|
TEST(meta_type_equivalent);
|
|
|
|
AP_Float f1;
|
|
AP_Float f2;
|
|
AP_Int8 i1;
|
|
|
|
REQUIRE(AP_Meta_class::meta_type_equivalent(&f1, &f2));
|
|
REQUIRE(!AP_Meta_class::meta_type_equivalent(&f1, &i1));
|
|
}
|
|
|
|
|
|
// MetaClass: external handles
|
|
{
|
|
TEST(meta_handle);
|
|
|
|
AP_Float f(0);
|
|
AP_Meta_class::Meta_handle h = f.meta_get_handle();
|
|
|
|
REQUIRE(0 != h);
|
|
REQUIRE(NULL != AP_Meta_class::meta_validate_handle(h));
|
|
REQUIRE(NULL == AP_Meta_class::meta_validate_handle(h + 1));
|
|
}
|
|
|
|
// MetaClass: test meta_cast
|
|
{
|
|
TEST(meta_cast);
|
|
|
|
AP_Float f(0);
|
|
|
|
REQUIRE(NULL != AP_Meta_class::meta_cast<AP_Float>(&f));
|
|
REQUIRE(NULL == AP_Meta_class::meta_cast<AP_Int8>(&f));
|
|
}
|
|
|
|
// MetaClass: ... insert tests here ...
|
|
|
|
// AP_Var: constants
|
|
{
|
|
TEST(var_constants);
|
|
|
|
REQUIRE(AP_Float_zero == 0);
|
|
REQUIRE(AP_Float_unity == 1.0);
|
|
REQUIRE(AP_Float_negative_unity = -1.0);
|
|
}
|
|
|
|
// AP_Var: initial value
|
|
{
|
|
TEST(var_initial_value);
|
|
|
|
AP_Float f1(12.345);
|
|
AP_Float f2;
|
|
|
|
REQUIRE(f1 == 12.345);
|
|
REQUIRE(f2 == 0);
|
|
}
|
|
|
|
// AP_Var: set, get, assignment
|
|
{
|
|
TEST(var_set_get);
|
|
|
|
AP_Float f(1.0);
|
|
|
|
REQUIRE(f == 1.0);
|
|
REQUIRE(f.get() == 1.0);
|
|
|
|
f.set(10.0);
|
|
REQUIRE(f == 10.0);
|
|
REQUIRE(f.get() == 10.0);
|
|
}
|
|
|
|
// AP_Var: cast to type
|
|
{
|
|
TEST(var_cast_to_type);
|
|
|
|
AP_Float f(1.0);
|
|
|
|
f *= 2.0;
|
|
REQUIRE(f == 2.0);
|
|
f /= 4;
|
|
REQUIRE(f == 0.5);
|
|
f += f;
|
|
REQUIRE(f == 1.0);
|
|
}
|
|
|
|
// AP_Var: equality
|
|
{
|
|
TEST(var_equality);
|
|
|
|
AP_Float f1(1.0);
|
|
AP_Float f2(1.0);
|
|
AP_Float f3(2.0);
|
|
|
|
REQUIRE(f1 == f2);
|
|
REQUIRE(f2 != f3);
|
|
}
|
|
|
|
// AP_Var: naming
|
|
{
|
|
TEST(var_naming);
|
|
|
|
AP_Float f(0, AP_Var::k_key_none, PSTR("test"));
|
|
char name_buffer[16];
|
|
|
|
f.copy_name(name_buffer, sizeof(name_buffer));
|
|
REQUIRE(!strcmp(name_buffer, "test"));
|
|
}
|
|
|
|
// AP_Var: serialize
|
|
// note that this presumes serialisation to the native in-memory format
|
|
{
|
|
TEST(var_serialize);
|
|
|
|
float b = 0;
|
|
AP_Float f(10.0);
|
|
size_t s;
|
|
|
|
s = f.serialize(&b, sizeof(b));
|
|
REQUIRE(s == sizeof(b));
|
|
REQUIRE(b == 10.0);
|
|
}
|
|
|
|
// AP_Var: unserialize
|
|
{
|
|
TEST(var_unserialize);
|
|
|
|
float b = 10;
|
|
AP_Float f(0);
|
|
size_t s;
|
|
|
|
s = f.unserialize(&b, sizeof(b));
|
|
REQUIRE(s == sizeof(b));
|
|
REQUIRE(f == 10);
|
|
}
|
|
|
|
// AP_Var: groups and names
|
|
{
|
|
TEST(group_names);
|
|
|
|
AP_Var_group group(AP_Var::k_key_none, PSTR("group_"));
|
|
AP_Float f(&group, 1, 1.0, PSTR("test"));
|
|
char name_buffer[16];
|
|
|
|
f.copy_name(name_buffer, sizeof(name_buffer));
|
|
REQUIRE(!strcmp(name_buffer, "group_test"));
|
|
}
|
|
|
|
// AP_Var: enumeration
|
|
{
|
|
TEST(empty_variables);
|
|
|
|
REQUIRE(AP_Var::first() == NULL);
|
|
}
|
|
|
|
{
|
|
TEST(enumerate_variables);
|
|
|
|
AP_Float f1;
|
|
|
|
REQUIRE(AP_Var::first() == &f1);
|
|
|
|
{
|
|
AP_Var_group group;
|
|
AP_Var f2(&group, 0, 0);
|
|
AP_Var f3(&group, 1, 0);
|
|
AP_Var *vp;
|
|
|
|
vp = AP_Var::first();
|
|
REQUIRE(vp == &group); // XXX presumes FIFO insertion
|
|
vp = vp->next();
|
|
REQUIRE(vp == &f1); // XXX presumes FIFO insertion
|
|
vp = vp->next();
|
|
REQUIRE(vp == &f2); // first variable in the grouped list
|
|
|
|
vp = AP_Var::first_member(&group);
|
|
REQUIRE(vp == &f2);
|
|
vp = vp->next_member();
|
|
REQUIRE(vp == &f3);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// AP_Var: enumeration
|
|
// note that this test presumes the singly-linked list implementation of the list
|
|
{
|
|
TEST(var_enumeration);
|
|
|
|
AP_Var *v = AP_Var::lookup_by_index(0);
|
|
|
|
// test basic enumeration
|
|
AP_Float f1(0, AP_Var::k_key_none, PSTR("test1"));
|
|
REQUIRE(AP_Var::lookup_by_index(0) == &f1);
|
|
REQUIRE(AP_Var::lookup_by_index(1) == v);
|
|
|
|
// test that new entries arrive in order
|
|
{
|
|
AP_Float f2(0, AP_Var::k_key_none, PSTR("test2"));
|
|
REQUIRE(AP_Var::lookup_by_index(0) == &f2);
|
|
REQUIRE(AP_Var::lookup_by_index(1) == &f1);
|
|
REQUIRE(AP_Var::lookup_by_index(2) == v);
|
|
|
|
{
|
|
AP_Float f3(0, AP_Var::k_key_none, PSTR("test3"));
|
|
REQUIRE(AP_Var::lookup_by_index(0) == &f3);
|
|
REQUIRE(AP_Var::lookup_by_index(1) == &f2);
|
|
REQUIRE(AP_Var::lookup_by_index(2) == &f1);
|
|
REQUIRE(AP_Var::lookup_by_index(3) == v);
|
|
}
|
|
}
|
|
|
|
// test that destruction removes from the list
|
|
REQUIRE(AP_Var::lookup_by_index(0) == &f1);
|
|
REQUIRE(AP_Var::lookup_by_index(1) == v);
|
|
}
|
|
#endif
|
|
|
|
#if SAVE
|
|
// AP_Var: load and save
|
|
{
|
|
TEST(var_load_save);
|
|
|
|
AP_Float f1(10, 4);
|
|
AP_Float f2(0, 4);
|
|
|
|
f2.save();
|
|
f2 = 1.0;
|
|
f2.load();
|
|
REQUIRE(f2 == 0);
|
|
|
|
f1.save();
|
|
f2.load();
|
|
REQUIRE(f2 == 10);
|
|
}
|
|
|
|
// AP_Var: group load/save
|
|
{
|
|
TEST(var_group_loadsave);
|
|
|
|
AP_Var_group group(PSTR("group_"), 4);
|
|
AP_Float f1(10.0, 8);
|
|
AP_Float f2(1.0, 4, PSTR("var"), &group);
|
|
|
|
f1.save();
|
|
f1.load();
|
|
REQUIRE(f1 == 10);
|
|
|
|
f2.save();
|
|
f2.load();
|
|
REQUIRE(f2 == 1);
|
|
|
|
f1.load();
|
|
REQUIRE(f1 == 1);
|
|
}
|
|
|
|
// AP_Var: derived types
|
|
{
|
|
TEST(var_derived);
|
|
|
|
AP_Float16 f(10.0, 20);
|
|
|
|
f.save();
|
|
f = 0;
|
|
REQUIRE(f == 0);
|
|
f.load();
|
|
REQUIRE(f = 10.0);
|
|
}
|
|
#endif
|
|
|
|
Test::report();
|
|
}
|
|
|
|
void
|
|
loop(void)
|
|
{
|
|
}
|