lundi 1 mars 2021

Cataloguing string literals passed to a specific function (data driving in C++ and testing)

I have a C++ application that's not allowed to change much (legacy code), and it relies on a large set of constants in C header files to function (custom/proprietary music/audio mixing device).

The device has occasionally had to undergo changes where certain pieces of hardware have been swapped out, and we get a C header file that gives a list of memory locations and names to enable/disable functionality in the overall audio device, e.g.:

#define PCM_BASE 0x8000000
#define PCM_BASE_CHANNEL_0 0x80010000
#define PCM_BASE_CHANNEL_1 0x80020000

We are now using a new "PCM chip" (i.e. audio hardware) that supports multiple modes of operation (i.e. different sample rates, such as 8kHz, 11kHz, 48kHz). The code I'm working with was poorly designed, and can't support multiple "modes" without completely re-writing it (not allowed to do this; I'll be fired if I do). I now have 4 sets of header files that have the exact same macro names (i.e. like in the example above), but different values.

So, there are 2 immediate solutions I can think of:

  1. Compile multiple versions of the software (i.e. one for each "mode"; management might let me do it, but they want to avoid it, since customers will be annoyed at having to launch/close instances of the same app when they want to change the audio "mode").

  2. The vendor supplies a JSON formatted copy of these values as a "JSON catalogue", categorized by "mode" (example below; no obvious/guaranteed pattern to number scheme).

    {
      "8K": {
        "PCM_BASE": "0x8000000",
        "PCM_BASE_CHANNEL_0": "0x80010000",
        "PCM_BASE_CHANNEL_1": "0x80020000"
      },
      "11K": {
        "PCM_BASE": "0x8010000",
        "PCM_BASE_CHANNEL_0": "0x80110000",
        "PCM_BASE_CHANNEL_1": "0x80120000"
      },
      "48K": {
        "PCM_BASE": "0x8090000",
        "PCM_BASE_CHANNEL_0": "0x80910000",
        "PCM_BASE_CHANNEL_1": "0x80940000"
      }
    }
    

My solution so far: I wrote a simple parser that reads the JSON values from the vendor-supplied JSON "catalogue", and read/write those memory addresses using a simple getter/setter class I wrote (instead of directly writing to those memory addresses via the C header files).

My problem: My code now contains a lot of string literals, e.g.:


Old code:

 #include <stdint.h>
 #include "pcm_memory_vendor.h"
 uint32_t* pcm = PCM_BASE;
 // Turn chip on.
 *pcm = 1;

New code:

 MemoryHandler mem();
 if (mode.is_8k()) {
     mem.write("PCM_BASE", "8k", 1)
 }
 

My problem: is there some decorator or unit testing framework/tool I can use to "audit" my code to validate the string literals passed to my write() function, but at compile time? I want to, for example, make sure that a rare use case (i.e. block of code that's rarely touched, even by code coverage tests) is actually trying to search for a valid memory address (i.e. valid string literal).

I know I could accomplish this by writing a parser that converts the JSON "catalogue" into a bunch of C++ definitions (i.e. generates a header file full of constexpr strings, and have my code directly use those string definitions by including this new header file in my code base at compile time), but I'd like to keep this data-driven/run-time approach (makes it easier for the QA team to write shell scripts and Python scripts by directly using this JSON catalogue, instead of having to write scripts that call C/C++ CLI tools).

I also thought of just greping my code base, but that's not a guarantee either. e.g., the following string literal could be caught:

mem.write("PCM_BASE", "11k", 1);

But the following would not, and is valid C++:

mem.write(
    "PCM_BASE",
    "11k",
    1);

To the point: is there some syntactic sugar, code decorator, or (simple) C++ testing framework that would allow me to audit/track arguments (i.e. string literals) passed to my function, or do I just have to bit the bullet and write a parser that converts all these dynamically-queried JSON values to compile-time constants I "bake in" to my C++ program?

Thanks!!!

Aucun commentaire:

Enregistrer un commentaire