Program Listing for File toml_config_test.cpp

Program Listing for File toml_config_test.cpp#

↰ Return to documentation for file (Test/commit/toml_config_test.cpp)

#include "kataglyphis_test_support.h"

#include <gtest/gtest.h>

#include <string>
#include <string_view>
#include <vector>

#include "kShippedInferenceConfig.inc"

import kataglyphis.toml_config;

namespace cfg = kataglyphis::config;
using kataglyphis::test::TempFile;

namespace {

constexpr std::string_view kFullConfig = R"(
[model]
model_path = "models/custom.onnx"
framework = "tflite"
input_width = 320
input_height = 256
confidence_threshold = 0.6
iou_threshold = 0.3
labels = ["cat", "dog"]

[pipeline]
camera_device = "/dev/video2"
capture_width = 1920
capture_height = 1080
capture_fps = 60
enable_inference = false
enable_overlay = false

[general]
log_level = "debug"
)";

}// namespace

TEST(TomlConfig, DefaultsDescribeTheCocoDetector)
{
    const auto config = cfg::get_default_inference_config();
    EXPECT_TRUE(config.model.model_path.empty());
    EXPECT_EQ(config.model.framework, "onnx");
    EXPECT_EQ(config.model.input_width, 640U);
    EXPECT_EQ(config.model.input_height, 640U);
    EXPECT_DOUBLE_EQ(config.model.confidence_threshold, 0.25);
    EXPECT_DOUBLE_EQ(config.model.iou_threshold, 0.45);
    ASSERT_EQ(config.model.labels.size(), 10U);
    EXPECT_EQ(config.model.labels.front(), "person");
    EXPECT_EQ(config.model.labels.back(), "traffic light");
    EXPECT_EQ(config.pipeline.camera_device, "0");
    EXPECT_EQ(config.pipeline.capture_width, 1280U);
    EXPECT_EQ(config.pipeline.capture_height, 720U);
    EXPECT_EQ(config.pipeline.capture_fps, 30U);
    EXPECT_TRUE(config.pipeline.enable_inference);
    EXPECT_TRUE(config.pipeline.enable_overlay);
    EXPECT_EQ(config.log_level, "info");
}

TEST(TomlConfig, EmptyDocumentKeepsTheStructDefaultsWithoutLabels)
{
    const auto config = cfg::parse_inference_config("");
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->model.input_width, 640U);
    EXPECT_EQ(config->pipeline.capture_fps, 30U);
    EXPECT_EQ(config->log_level, "info");
    // Unlike get_default_inference_config(), parsing starts from no labels at all.
    EXPECT_TRUE(config->model.labels.empty());
}

TEST(TomlConfig, ParsesEveryField)
{
    const auto config = cfg::parse_inference_config(std::string(kFullConfig));
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->model.model_path, "models/custom.onnx");
    EXPECT_EQ(config->model.framework, "tflite");
    EXPECT_EQ(config->model.input_width, 320U);
    EXPECT_EQ(config->model.input_height, 256U);
    EXPECT_DOUBLE_EQ(config->model.confidence_threshold, 0.6);
    EXPECT_DOUBLE_EQ(config->model.iou_threshold, 0.3);
    EXPECT_EQ(config->model.labels, (std::vector<std::string>{ "cat", "dog" }));
    EXPECT_EQ(config->pipeline.camera_device, "/dev/video2");
    EXPECT_EQ(config->pipeline.capture_width, 1920U);
    EXPECT_EQ(config->pipeline.capture_height, 1080U);
    EXPECT_EQ(config->pipeline.capture_fps, 60U);
    EXPECT_FALSE(config->pipeline.enable_inference);
    EXPECT_FALSE(config->pipeline.enable_overlay);
    EXPECT_EQ(config->log_level, "debug");
}

TEST(TomlConfig, PartialDocumentOnlyOverridesWhatItNames)
{
    const auto config = cfg::parse_inference_config("[pipeline]\ncapture_fps = 15\n");
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->pipeline.capture_fps, 15U);
    EXPECT_EQ(config->pipeline.capture_width, 1280U);
    EXPECT_EQ(config->model.input_width, 640U);
    EXPECT_EQ(config->model.framework, "onnx");
}

TEST(TomlConfig, MalformedDocumentsAreParseErrors)
{
    for (const std::string_view document : { "[model",
           "input_width = ",
           "[model]\ninput_width = 1\ninput_width = 2\n",
           "= 3",
           "[model]\nlabels = [\"a\"" }) {
        const auto config = cfg::parse_inference_config(std::string(document));
        ASSERT_FALSE(config.has_value()) << document;
        EXPECT_EQ(config.error(), cfg::TomlConfigError::ParseError) << document;
    }
}

TEST(TomlConfig, WrongTypesFallBackToTheDefaults)
{
    const auto config = cfg::parse_inference_config(R"(
[model]
model_path = 5
framework = true
input_width = "wide"
labels = "person"

[pipeline]
camera_device = 0
enable_inference = "yes"

[general]
log_level = 3
)");
    ASSERT_TRUE(config.has_value());
    EXPECT_TRUE(config->model.model_path.empty());
    EXPECT_EQ(config->model.framework, "onnx");
    EXPECT_EQ(config->model.input_width, 640U);
    EXPECT_TRUE(config->model.labels.empty());
    EXPECT_EQ(config->pipeline.camera_device, "0");
    EXPECT_TRUE(config->pipeline.enable_inference);
    EXPECT_EQ(config->log_level, "info");
}

TEST(TomlConfig, LabelArraysKeepOnlyTheirStrings)
{
    const auto config = cfg::parse_inference_config("[model]\nlabels = [1, \"cat\", true, \"dog\", 2.5]\n");
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->model.labels, (std::vector<std::string>{ "cat", "dog" }));
}

TEST(TomlConfig, OutOfRangeIntegersFallBackToTheDefaults)
{
    const auto config = cfg::parse_inference_config(
      "[model]\ninput_width = -1\ninput_height = 4294967296\n[pipeline]\ncapture_fps = -30\n");
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->model.input_width, 640U);
    EXPECT_EQ(config->model.input_height, 640U);
    EXPECT_EQ(config->pipeline.capture_fps, 30U);
}

TEST(TomlConfig, IntegerThresholdsReadAsDoubles)
{
    const auto config = cfg::parse_inference_config("[model]\nconfidence_threshold = 1\niou_threshold = 0\n");
    ASSERT_TRUE(config.has_value());
    EXPECT_DOUBLE_EQ(config->model.confidence_threshold, 1.0);
    EXPECT_DOUBLE_EQ(config->model.iou_threshold, 0.0);
}

TEST(TomlConfig, TheShippedConfigParses)
{
    const auto config = cfg::parse_inference_config(std::string(kShippedInferenceConfig));
    ASSERT_TRUE(config.has_value());
    EXPECT_EQ(config->model.model_path, "models/deim_dfine_n_coco.onnx");
    EXPECT_EQ(config->model.framework, "onnx");
    EXPECT_EQ(config->model.input_width, 640U);
    EXPECT_EQ(config->model.input_height, 640U);
    ASSERT_EQ(config->model.labels.size(), 80U);
    EXPECT_EQ(config->model.labels.front(), "person");
    EXPECT_EQ(config->model.labels.back(), "toothbrush");
    EXPECT_EQ(config->pipeline.capture_width, 1280U);
    EXPECT_EQ(config->pipeline.capture_height, 720U);
    EXPECT_EQ(config->pipeline.capture_fps, 30U);
    EXPECT_EQ(config->log_level, "info");
}

TEST(TomlConfig, LoadsTheSameConfigFromAFile)
{
    const TempFile file("kataglyphis-inference", ".toml", kFullConfig);
    const auto loaded = cfg::load_inference_config(file.path());
    const auto parsed = cfg::parse_inference_config(std::string(kFullConfig));
    ASSERT_TRUE(loaded.has_value());
    ASSERT_TRUE(parsed.has_value());
    EXPECT_EQ(loaded->model.model_path, parsed->model.model_path);
    EXPECT_EQ(loaded->model.labels, parsed->model.labels);
    EXPECT_EQ(loaded->pipeline.capture_fps, parsed->pipeline.capture_fps);
    EXPECT_EQ(loaded->log_level, parsed->log_level);
}

TEST(TomlConfig, MissingFileIsFileNotFound)
{
    const auto config = cfg::load_inference_config(kataglyphis::test::missing_path("inference.toml"));
    ASSERT_FALSE(config.has_value());
    EXPECT_EQ(config.error(), cfg::TomlConfigError::FileNotFound);
}

TEST(TomlConfig, MalformedFileIsAParseError)
{
    const TempFile file("kataglyphis-inference-broken", ".toml", "[model\n");
    const auto config = cfg::load_inference_config(file.path());
    ASSERT_FALSE(config.has_value());
    EXPECT_EQ(config.error(), cfg::TomlConfigError::ParseError);
}