Skip to content

Commit

Permalink
Increase test coverage of C code [AP-949] (#1377)
Browse files Browse the repository at this point in the history
# Description

@swift-nav/devinfra

Increase the test coverage of C code by rewriting the template for the
V4 C++ tests

This is a complete rewrite of the existing template which covers the
following test cases:
- Behaviour of `*_encoded_len()`
- Encoding payload directly to a user-provided buffer
  - Underflow errors and alternative uses
- Decoding payload from a user provided buffer
  - Underflow errors and alternative uses
- Sending and receiving complete frame through C API (`sbp_state_t`)
- Sending and receiving complete frame through C++ API (`sbp::State` and
`sbp::MessageHandler<>`)
- Encoding/decoding payload through C++ API
- Comparison functions and operators with all potential mismatches
covered automatically
- C++ type traits
- All string functions generated as part of the API for each message
which contains string fields

This comprehensive template covers 100% of generated V4 code. No attempt
was made to increase coverage of the legacy API, although there is
little code to test anyway.

This rewrite by itself increases code coverage from ~20% to ~55% just
based on the existing test cases.

Coverage can be further increased by introducing new test cases for the
120 or so messages which are currently uncovered. This is done on a
separate PR #1382 and brings
coverage up to ~99% (generated locally with lcov, sonar cloud seems to
have a different way of calculating it)

To keep things a little smaller this PR will not introduce the new test
cases, they will be kept separate and merged in to this branch before
going to master

To aid with reviewing the commits are broken up to logical steps. The
first couple deal with some supporting changes such as altering the
generate to pass through some extra meta information (the generated
companion fields for variable length arrays were already present to some
extent in the previous template, but the information provided was not
sufficient to get complete test coverage)

Next there are some minor alterations to some existing test cases. These
all follow the same pattern of only affecting messages which have
variable length arrays or string. For variable length arrays the
existing specification for the companion "count" fields is extended out
with 2 extra bits of information, for encoded strings there is one new
fields. Both of these are required in order to get 100% coverage in the
new template.

Finally, all code is regenerated. The final commit makes up the vast
majority of changes in this PR. I suggest concentrating on just a single
test case along with the code template itself, once these are understood
all the other generated files can be treated with confidence.

Sonar cloud is not reporting any code coverage for this PR because there
are no changes to actual code in libsbp, only the test case source code
which isn't included in the calculation. You can see the effect of this
PR by following the sonar cloud link an noting the "estimated after
merge" number.

*For Reviewers*
Suggested places to concentrate on:
- `generator/sbpg/targets/resources/c/test/v4/sbp_cpp_test.cc.j2` - The
main template which was rewritten for this PR
- `spec/tests/yaml/swiftnav/sbp/logging/test_MsgFwd.yaml` - for an
example of how the meta information for variable length arrays has
changed
- `c/test/cpp/auto_check_sbp_logging_MsgFwd.cc` - generated output of
above test case
-
`spec/tests/yaml/swiftnav/sbp/settings/test_MsgSettingsReadByIndexResp.yaml`
- for an example of how the meta information for encoded strings has
changed
- `c/test/cpp/auto_check_sbp_settings_MsgSettingsReadByIndexDone.cc` -
generated output of above test case

# API compatibility

Does this change introduce a API compatibility risk?

No

## API compatibility plan

If the above is "Yes", please detail the compatibility (or migration)
plan:

N/A

# JIRA Reference

https://swift-nav.atlassian.net/browse/AP-949
  • Loading branch information
woodfell authored Nov 22, 2023
1 parent b2fce6d commit a067434
Show file tree
Hide file tree
Showing 1,053 changed files with 758,836 additions and 46,052 deletions.
178 changes: 178 additions & 0 deletions c/test/auto_check_sbp_acquisition_MsgAcqResult.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright (C) 2015-2021 Swift Navigation Inc.
* Contact: https://support.swiftnav.com
*
* This source is subject to the license found in the file 'LICENSE' which must
* be be distributed together with this source. All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*/

// This file was auto-generated from
// spec/tests/yaml/swiftnav/sbp/acquisition/test_MsgAcqResult.yaml by
// generate.py. Do not modify by hand!

#include <check.h>
#include <libsbp/sbp.h>
#include <libsbp/v4/acquisition.h>
#include <stdio.h> // for debugging
#include <stdlib.h> // for malloc

static struct {
u32 n_callbacks_logged;
u16 sender_id;
sbp_msg_type_t msg_type;
sbp_msg_t msg;
void *context;
} last_msg;

static u32 dummy_wr = 0;
static u32 dummy_rd = 0;
static u8 dummy_buff[1024];
static void *last_io_context;

static void *DUMMY_MEMORY_FOR_CALLBACKS = (void *)0xdeadbeef;
static void *DUMMY_MEMORY_FOR_IO = (void *)0xdead0000;

static void dummy_reset() {
dummy_rd = dummy_wr = 0;
memset(dummy_buff, 0, sizeof(dummy_buff));
}

static s32 dummy_write(u8 *buff, u32 n, void *context) {
last_io_context = context;
u32 real_n = n; //(dummy_n > n) ? n : dummy_n;
memcpy(dummy_buff + dummy_wr, buff, real_n);
dummy_wr += real_n;
return (s32)real_n;
}

static s32 dummy_read(u8 *buff, u32 n, void *context) {
last_io_context = context;
u32 real_n = n; //(dummy_n > n) ? n : dummy_n;
memcpy(buff, dummy_buff + dummy_rd, real_n);
dummy_rd += real_n;
return (s32)real_n;
}

static void logging_reset() { memset(&last_msg, 0, sizeof(last_msg)); }

static void msg_callback(u16 sender_id, sbp_msg_type_t msg_type,
const sbp_msg_t *msg, void *context) {
last_msg.n_callbacks_logged++;
last_msg.sender_id = sender_id;
last_msg.msg_type = msg_type;
last_msg.msg = *msg;
last_msg.context = context;
}

START_TEST(test_auto_check_sbp_acquisition_MsgAcqResult) {
static sbp_msg_callbacks_node_t n;

// State of the SBP message parser.
// Must be statically allocated.
sbp_state_t sbp_state;

//
// Run tests:
//
// Test successful parsing of a message
{
// SBP parser state must be initialized before sbp_process is called.
// We re-initialize before every test so that callbacks for the same message
// types can be
// allocated multiple times across different tests.
sbp_state_init(&sbp_state);

sbp_state_set_io_context(&sbp_state, &DUMMY_MEMORY_FOR_IO);

logging_reset();

sbp_callback_register(&sbp_state, 0x2f, &msg_callback,
&DUMMY_MEMORY_FOR_CALLBACKS, &n);

u8 encoded_frame[] = {
85, 47, 0, 195, 4, 14, 0, 0, 104, 65, 102,
102, 144, 66, 205, 196, 0, 70, 8, 0, 207, 189,
};

dummy_reset();

sbp_msg_t test_msg;
memset(&test_msg, 0, sizeof(test_msg));

test_msg.acq_result.cf = 8241.2001953125;

test_msg.acq_result.cn0 = 14.5;

test_msg.acq_result.cp = 72.19999694824219;

test_msg.acq_result.sid.code = 0;

test_msg.acq_result.sid.sat = 8;

sbp_message_send(&sbp_state, SbpMsgAcqResult, 1219, &test_msg,
&dummy_write);

ck_assert_msg(dummy_wr == sizeof(encoded_frame),
"not enough data was written to dummy_buff (expected: %zu, "
"actual: %zu)",
sizeof(encoded_frame), dummy_wr);
ck_assert_msg(memcmp(dummy_buff, encoded_frame, sizeof(encoded_frame)) == 0,
"frame was not encoded properly");

while (dummy_rd < dummy_wr) {
ck_assert_msg(sbp_process(&sbp_state, &dummy_read) >= SBP_OK,
"sbp_process threw an error!");
}

ck_assert_msg(last_msg.n_callbacks_logged == 1,
"msg_callback: one callback should have been logged");
ck_assert_msg(last_msg.sender_id == 1219,
"msg_callback: sender_id decoded incorrectly");

ck_assert_msg(
sbp_message_cmp(SbpMsgAcqResult, &last_msg.msg, &test_msg) == 0,
"Sent and received messages did not compare equal");

ck_assert_msg(
(last_msg.msg.acq_result.cf * 100 - 8241.20019531 * 100) < 0.05,
"incorrect value for last_msg.msg.acq_result.cf, expected "
"8241.20019531, is %s",
last_msg.msg.acq_result.cf);

ck_assert_msg(
(last_msg.msg.acq_result.cn0 * 100 - 14.5 * 100) < 0.05,
"incorrect value for last_msg.msg.acq_result.cn0, expected 14.5, is %s",
last_msg.msg.acq_result.cn0);

ck_assert_msg(
(last_msg.msg.acq_result.cp * 100 - 72.1999969482 * 100) < 0.05,
"incorrect value for last_msg.msg.acq_result.cp, expected "
"72.1999969482, is %s",
last_msg.msg.acq_result.cp);

ck_assert_msg(last_msg.msg.acq_result.sid.code == 0,
"incorrect value for last_msg.msg.acq_result.sid.code, "
"expected 0, is %d",
last_msg.msg.acq_result.sid.code);

ck_assert_msg(last_msg.msg.acq_result.sid.sat == 8,
"incorrect value for last_msg.msg.acq_result.sid.sat, "
"expected 8, is %d",
last_msg.msg.acq_result.sid.sat);
}
}
END_TEST

Suite *auto_check_sbp_acquisition_MsgAcqResult_suite(void) {
Suite *s = suite_create(
"SBP generated test suite: auto_check_sbp_acquisition_MsgAcqResult");
TCase *tc_acq =
tcase_create("Automated_Suite_auto_check_sbp_acquisition_MsgAcqResult");
tcase_add_test(tc_acq, test_auto_check_sbp_acquisition_MsgAcqResult);
suite_add_tcase(s, tc_acq);
return s;
}
Loading

0 comments on commit a067434

Please sign in to comment.