Skip to content

Commit

Permalink
Use plain path instead of URI for resourcePath (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
filip-stenstrom authored Oct 29, 2024
1 parent dffae5e commit aec4c76
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 22 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Note that version 2.1 is the first version with release notes. Please see the co
- Fixed an issue where enum variables min/max attributes were incorrectly handled as `int32`, instead of `int64`.
- [BREAKING] Changed return types of `fmi3_import_get_enum_variable_min` and `fmi3_import_get_enum_variable_max` from `int` to `fmi3_int64_t`.
- For FMI3, added a missing trailing file separator to `resourcePath`.
- For FMI3, removed `file` URI prefix for `resourcePath`.

### Improvements

Expand Down
80 changes: 80 additions & 0 deletions Test/FMI3/fmi3_import_sim_me_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,83 @@ TEST_CASE("Model-Exchange FMU example") {
REQUIRE(fmi_import_rmdir(&callbacks, tmpPath) == jm_status_success);
callbacks.free((void*)tmpPath);
}

static char loggedResourcePath[4096];

// If a log message is output on this format: <PREFIX>=<VALUE>, then copy value to testedResourcePath.
static void test_logger_fmi3Instantiate (fmi3_instance_environment_t instanceEnvironment,
fmi3_status_t status, fmi3_string_t category, fmi3_string_t message)
{
char prefix[20] = "TEST_RESOURCE_PATH=";
if (strncmp(message, "TEST_RESOURCE_PATH=", strlen(prefix)) == 0) {
strcpy(loggedResourcePath, message + strlen(prefix));
}
}

TEST_CASE("Test fallback/default value(s) passed to fmi3Instantiate") {
const char* tmpPath;
jm_callbacks callbacks;
fmi_import_context_t* context;
fmi_version_enu_t version;
jm_status_enu_t jmstatus;

const char* FMUPath = FMU3_ME_PATH;

callbacks.malloc = malloc;
callbacks.calloc = calloc;
callbacks.realloc = realloc;
callbacks.free = free;
callbacks.logger = jm_default_logger;
callbacks.log_level = jm_log_level_debug;
callbacks.context = 0;

#ifdef FMILIB_GENERATE_BUILD_STAMP
printf("Library build stamp:\n%s\n", fmilib_get_build_stamp());
#endif

tmpPath = fmi_import_mk_temp_dir(&callbacks, FMU_UNPACK_DIR, NULL);
REQUIRE(tmpPath != nullptr);

context = fmi_import_allocate_context(&callbacks);
REQUIRE(context != nullptr);
REQUIRE(fmi_import_get_fmi_version(context, FMU3_ME_PATH, tmpPath) == fmi_version_3_0_enu);

fmi3_testutil_import_t* tfmu = fmi3_testutil_parse_xml_with_log(tmpPath);
fmi3_import_t* fmu = tfmu->fmu;
REQUIRE(fmu != nullptr);

// TODO: Various issues related to parsing of Annotations
REQUIRE(fmi3_testutil_get_num_problems(tfmu) == 5);

REQUIRE((fmi3_import_get_fmu_kind(fmu) & fmi3_fmu_kind_me) == fmi3_fmu_kind_me);

// Set logger:
REQUIRE(fmi3_import_create_dllfmu(fmu, fmi3_fmu_kind_me, NULL, test_logger_fmi3Instantiate) == jm_status_success);

jmstatus = fmi3_import_instantiate_model_exchange(
fmu,
"InstanceName",
NULL,
fmi3_false,
fmi3_false
);
REQUIRE(jmstatus == jm_status_success);

// Main part of this test:
char expected[4096];
strcpy(expected, tmpPath);
#ifdef WIN32
strcpy(expected + strlen(expected), "\\resources\\");
#else
strcpy(expected + strlen(expected), "/resources/");
#endif
REQUIRE(strcmp(expected, loggedResourcePath) == 0);

// Clean up
REQUIRE(fmi3_import_terminate(fmu) == fmi3_status_ok);
fmi3_import_free_instance(fmu);
fmi3_testutil_import_free(tfmu);
fmi_import_free_context(context);
REQUIRE(fmi_import_rmdir(&callbacks, tmpPath) == jm_status_success);
callbacks.free((void*)tmpPath);
}
5 changes: 5 additions & 0 deletions Test/FMI3/fmu_dummy/fmu3_model_me.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ FMI3_Export fmi3Instance fmi3InstantiateModelExchange(
fmi3InstanceEnvironment instanceEnvironment,
fmi3LogMessageCallback logMessage)
{
// For testing:
char msg[4096] = "TEST_RESOURCE_PATH=";
strcpy(msg + strlen(msg), resourcePath);
logMessage(instanceEnvironment, fmi3OK, "Debug", msg);

return fmi_instantiate(fmu_type_me,
instanceName,
instantiationToken,
Expand Down
60 changes: 38 additions & 22 deletions src/Import/src/FMI3/fmi3_import.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,46 +88,50 @@ fmi3_import_t* fmi3_import_parse_xml(
fmi_import_context_t* context, const char* dirPath, fmi3_xml_callbacks_t* xml_callbacks) {
char* xmlPath;
char* terminalsAndIconsPath;
char absPath[FILENAME_MAX + 2];
size_t resourcePathLen;
fmi3_import_t* fmu = NULL;

if (strlen(dirPath) + 20 > FILENAME_MAX) {
jm_log_fatal(context->callbacks, module, "Directory path for FMU is too long");
return NULL;
}

xmlPath = fmi_import_get_model_description_path(dirPath, context->callbacks);
xmlPath = fmi_import_get_model_description_path(dirPath, context->callbacks);
terminalsAndIconsPath = fmi_import_get_terminals_and_icons_path(dirPath, context->callbacks);
fmu = fmi3_import_allocate(context->callbacks);

if (!fmu) {
context->callbacks->free(xmlPath);
if (terminalsAndIconsPath) {
context->callbacks->free(terminalsAndIconsPath);
}
return NULL;
goto err1;
}

if (jm_get_dir_abspath(context->callbacks, dirPath, absPath, FILENAME_MAX + 2)) {
size_t len = strlen(absPath);
// Compared to FMI2, in FMI3 we need to add a trailing file separator below
strcpy(absPath + len, FMI_FILE_SEP "resources" FMI_FILE_SEP);
fmu->resourcePath = fmi_import_create_URL_from_abs_path(context->callbacks, absPath);

// Create the resourcePath
fmu->resourcePath = context->callbacks->malloc(FILENAME_MAX + 2);
if (!fmu->resourcePath) {
jm_log_fatal(context->callbacks, "FMILIB", "Could not allocate memory");
goto err2;
}
// Set fmu->resourcePath to abspath of dirPath
if (!jm_get_dir_abspath(context->callbacks, dirPath, fmu->resourcePath, FILENAME_MAX + 2)) {
goto err2;
}
// Append the resource dir. Compared to FMI 2, in FMI 3 the resourcePath:
// - Is an absolute path (not a URI)
// - Needs a trailing file separator
resourcePathLen = strlen(fmu->resourcePath);
if (resourcePathLen + 20 > FILENAME_MAX) {
jm_log_fatal(context->callbacks, module, "Resource directory path for FMU is too long");
goto err2;
}
strcpy(fmu->resourcePath + resourcePathLen, FMI_FILE_SEP "resources" FMI_FILE_SEP);

// Create dirPath
fmu->dirPath = context->callbacks->malloc(strlen(dirPath) + 1);
if (!fmu->dirPath || !fmu->resourcePath) {
if (!fmu->dirPath) {
jm_log_fatal(context->callbacks, "FMILIB", "Could not allocate memory");
fmi3_import_free(fmu);
context->callbacks->free(xmlPath);
if (terminalsAndIconsPath) {
context->callbacks->free(terminalsAndIconsPath);
}
return NULL;
goto err2;
}
strcpy(fmu->dirPath, dirPath);

jm_log_verbose(context->callbacks, "FMILIB", "Parsing model description XML");

if (fmi3_xml_parse_model_description(fmu->md, xmlPath, xml_callbacks)) {
fmi3_import_free(fmu);
fmu = NULL;
Expand Down Expand Up @@ -155,6 +159,18 @@ fmi3_import_t* fmi3_import_parse_xml(
}

return fmu;

// Error handling
err2:
fmi3_import_free(fmu);
fmu = NULL;
err1:
context->callbacks->free(xmlPath);
if (terminalsAndIconsPath) {
context->callbacks->free(terminalsAndIconsPath);
}
return NULL;

}

void fmi3_import_free(fmi3_import_t* fmu) {
Expand Down

0 comments on commit aec4c76

Please sign in to comment.