fix: share one language-test mutex; read the OFX marker via Win32 env
i18n: test_lock() and lang_test_lock() used to be TWO different static
mutexes, so the i18n tests and the ~30 app/actions/dialogs tests that
mutate the language global never excluded each other. Windows thread
scheduling exposed the race: tr_falls_back_to_english_then_the_key got
the English value because another test flipped the language mid-assert.
Both entry points now lock the same mutex.
oak_test_plugin.c: on Windows the plugin DLL has its own CRT
environment block, so getenv() never sees what the host's
std::env::set_var set via SetEnvironmentVariableW — the interact
lifecycle test's marker file stayed empty ("lifecycle actions
missing: []"). Read the marker path through GetEnvironmentVariableA
on _WIN32.
This commit is contained in:
@@ -35,6 +35,26 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Windows 上插件 DLL 带自己的 CRT 环境块:宿主 Rust 侧的
|
||||
* std::env::set_var 走 SetEnvironmentVariableW,只更新 Win32 进程
|
||||
* 环境,插件里 getenv 读的 CRT `_environ` 看不到它。marker 路径
|
||||
* 统一经 Win32 进程环境读取(POSIX 下就是 getenv)。 */
|
||||
static const char *marker_env(const char *name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static char buf[32768];
|
||||
DWORD n = GetEnvironmentVariableA(name, buf, (DWORD)sizeof buf);
|
||||
if (n == 0 || n >= sizeof buf)
|
||||
return NULL;
|
||||
return buf;
|
||||
#else
|
||||
return getenv(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "ofxCore.h"
|
||||
#include "ofxColour.h"
|
||||
@@ -99,7 +119,7 @@ static int g_button_instance_changed = 0;
|
||||
static void record_button_instance_changed(void)
|
||||
{
|
||||
g_button_instance_changed++;
|
||||
const char *marker = getenv("OAK_TEST_PLUGIN_INSTANCECHANGED_MARKER");
|
||||
const char *marker = marker_env("OAK_TEST_PLUGIN_INSTANCECHANGED_MARKER");
|
||||
if (!marker)
|
||||
return;
|
||||
FILE *f = fopen(marker, "a");
|
||||
@@ -593,7 +613,7 @@ static OfxStatus mainEntryID(const char *action, const void *handle,
|
||||
* (宿主测试断言用;未设环境变量时静默)。 */
|
||||
static void interact_record(const char *fmt, ...)
|
||||
{
|
||||
const char *marker = getenv("OAK_TEST_PLUGIN_INTERACT_MARKER");
|
||||
const char *marker = marker_env("OAK_TEST_PLUGIN_INTERACT_MARKER");
|
||||
if (!marker)
|
||||
return;
|
||||
FILE *f = fopen(marker, "a");
|
||||
|
||||
+6
-3
@@ -425,11 +425,14 @@ mod tests {
|
||||
/// Serializes tests that mutate the language global / HOME.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_lock() -> std::sync::MutexGuard<'static, ()> {
|
||||
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
||||
LOCK.lock().unwrap_or_else(|e| e.into_inner())
|
||||
lang_test_lock().lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
|
||||
/// Compatibility alias used by the app/actions test modules.
|
||||
/// Compatibility alias used by the app/actions test modules. Both entry
|
||||
/// points MUST share the one static mutex: with two separate mutexes the
|
||||
/// i18n tests and the app/actions tests do not exclude each other, and
|
||||
/// the language global races (observed as a Windows-only CI failure
|
||||
/// where `tr` returned the English value mid-test).
|
||||
#[cfg(test)]
|
||||
pub(crate) fn lang_test_lock() -> &'static std::sync::Mutex<()> {
|
||||
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
||||
|
||||
Reference in New Issue
Block a user