Repository: zng-ui/zng (language: rust)

Issue:
Config integration tests are failing
The error is only logged and we did not enable log panic.

Issue related with `Px` deserialization.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 362e65dca..0554aafc4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
 * Fix `WINDOWS.frame_image` capture with multiple windows capturing pixels from the wrong window.
 * Fix `WINDOWS.frame_image` var not updating on load or error.
 * Fix cursor not resetting on widget deinit.
+* Add missing `zng::app::test_log`.
 
 # 0.3.3
 
diff --git a/crates/zng-app/src/lib.rs b/crates/zng-app/src/lib.rs
index 0e066f54e..9189cb95c 100644
--- a/crates/zng-app/src/lib.rs
+++ b/crates/zng-app/src/lib.rs
@@ -743,6 +743,7 @@ impl HeadlessApp {
                 Err(t) => task = t,
             }
         }
+        task.cancel();
 
         None
     }
diff --git a/crates/zng-ext-config/src/toml.rs b/crates/zng-ext-config/src/toml.rs
index 9670fdd56..6fa7442f4 100644
--- a/crates/zng-ext-config/src/toml.rs
+++ b/crates/zng-ext-config/src/toml.rs
@@ -118,16 +118,18 @@ impl TryFrom<RawConfigValue> for serde_toml::Value {
             serde_json::Value::Null => return Err(TomlValueRawError::Null),
             serde_json::Value::Bool(b) => serde_toml::Value::Boolean(b),
             serde_json::Value::Number(n) => {
-                if let Some(f) = n.as_f64() {
-                    serde_toml::Value::Float(f)
-                } else if let Some(i) = n.as_i64() {
-                    serde_toml::Value::Integer(i)
-                } else {
-                    let i = n.as_u64().unwrap();
-                    if i > i64::MAX as u64 {
-                        return Err(TomlValueRawError::InvalidInt(i));
+                // serde_json does not implicit converts float to integer, so we try integers first here.
+                if let Some(n) = n.as_i64() {
+                    serde_toml::Value::Integer(n)
+                } else if let Some(n) = n.as_u64() {
+                    if n > i64::MAX as u64 {
+                        return Err(TomlValueRawError::InvalidInt(n));
                     }
-                    serde_toml::Value::Integer(i as i64)
+                    serde_toml::Value::Integer(n as i64)
+                } else if let Some(n) = n.as_f64() {
+                    serde_toml::Value::Float(n)
+                } else {
+                    unreachable!()
                 }
             }
             serde_json::Value::String(s) => serde_toml::Value::String(s),
diff --git a/crates/zng-ext-config/src/yaml.rs b/crates/zng-ext-config/src/yaml.rs
index 485255b90..e71052eb0 100644
--- a/crates/zng-ext-config/src/yaml.rs
+++ b/crates/zng-ext-config/src/yaml.rs
@@ -72,18 +72,21 @@ impl TryFrom<serde_yaml::Value> for RawConfigValue {
         let ok = match value {
             serde_yaml::Value::Null => serde_json::Value::Null,
             serde_yaml::Value::Bool(b) => serde_json::Value::Bool(b),
-            serde_yaml::Value::Number(n) => serde_json::Value::Number(if let Some(n) = n.as_f64() {
-                match serde_json::Number::from_f64(n) {
-                    Some(n) => n,
-                    None => return Err(YamlValueRawError::InvalidFloat(n)),
-                }
-            } else if let Some(i) = n.as_i64() {
-                i.into()
-            } else if let Some(i) = n.as_u64() {
-                i.into()
-            } else {
-                unreachable!()
-            }),
+            serde_yaml::Value::Number(n) => {
+                // serde_json does not implicit converts float to integer, so we try integers first here.
+                serde_json::Value::Number(if let Some(n) = n.as_i64() {
+                    n.into()
+                } else if let Some(n) = n.as_u64() {
+                    n.into()
+                } else if let Some(n) = n.as_f64() {
+                    match serde_json::Number::from_f64(n) {
+                        Some(n) => n,
+                        None => return Err(YamlValueRawError::InvalidFloat(n)),
+                    }
+                } else {
+                    unreachable!()
+                })
+            }
             serde_yaml::Value::String(s) => serde_json::Value::String(s),
             serde_yaml::Value::Sequence(s) => serde_json::Value::Array({
                 let mut r = Vec::with_capacity(s.len());
@@ -112,15 +115,18 @@ impl TryFrom<RawConfigValue> for serde_yaml::Value {
         let ok = match value.0 {
             serde_json::Value::Null => serde_yaml::Value::Null,
             serde_json::Value::Bool(b) => serde_yaml::Value::Bool(b),
-            serde_json::Value::Number(n) => serde_yaml::Value::Number(if let Some(f) = n.as_f64() {
-                serde_yaml::Number::from(f)
-            } else if let Some(n) = n.as_i64() {
-                serde_yaml::Number::from(n)
-            } else if let Some(n) = n.as_u64() {
-                serde_yaml::Number::from(n)
-            } else {
-                unreachable!()
-            }),
+            serde_json::Value::Number(n) => {
+                // serde_json does not implicit converts float to integer, so we try integers first here.
+                serde_yaml::Value::Number(if let Some(f) = n.as_i64() {
+                    serde_yaml::Number::from(f)
+                } else if let Some(n) = n.as_u64() {
+                    serde_yaml::Number::from(n)
+                } else if let Some(n) = n.as_f64() {
+                    serde_yaml::Number::from(n)
+                } else {
+                    unreachable!()
+                })
+            }
             serde_json::Value::String(s) => serde_yaml::Value::String(s),
             serde_json::Value::Array(a) => serde_yaml::Value::Sequence({
                 let mut r = Vec::with_capacity(a.len());
diff --git a/crates/zng/src/app.rs b/crates/zng/src/app.rs
index 4eb3cfaca..32f7f01a2 100644
--- a/crates/zng/src/app.rs
+++ b/crates/zng/src/app.rs
@@ -400,6 +400,10 @@ pub use zng_app::{
     print_tracing, AppControlFlow, AppEventObserver, AppExtended, AppExtension, AppExtensionBoxed, AppExtensionInfo, DInstant, Deadline,
     ExitRequestedArgs, HeadlessApp, InstantMode, EXIT_CMD, EXIT_REQUESTED_EVENT, INSTANT,
 };
+
+#[cfg(feature = "test_util")]
+pub use zng_app::test_log;
+
 pub use zng_app_context::{
     app_local, context_local, AppId, AppLocal, AppScope, CaptureFilter, ContextLocal, ContextValueSet, FullLocalContext, LocalContext,
     MappedRwLockReadGuardOwned, MappedRwLockWriteGuardOwned, ReadOnlyRwLock, RunOnDrop, RwLockReadGuardOwned, RwLockWriteGuardOwned,


Test patch:
diff --git a/tests/config.rs b/tests/config.rs
index bdb1d3cf2..280d9889b 100644
--- a/tests/config.rs
+++ b/tests/config.rs
@@ -38,6 +38,7 @@ fn test_config<C: AnyConfig>(file: &str, source: impl Fn(&Path) -> C) {
 
     fn run<C: AnyConfig>(source: impl Fn() -> C, test_read: bool) {
         let mut app = APP.defaults().run_headless(false);
+        zng::app::test_log();
 
         CONFIG.load(source());
         app.run_task(async {
@@ -212,6 +213,7 @@ fn concurrent_read_write() {
         // setup
         rmv_file_assert(&file);
         let mut app = APP.defaults().run_headless(false);
+        zng::app::test_log();
         CONFIG.load(JsonConfig::sync(&file));
         CONFIG.get("key", || Txt::from_static("default/custom")).set("custom").unwrap();
 
@@ -231,6 +233,7 @@ fn concurrent_read_write() {
         .map(|_| {
             std::thread::spawn(clmv!(file, || {
                 let mut app = APP.defaults().run_headless(false);
+                zng::app::test_log();
                 CONFIG.load(JsonConfig::sync(file));
 
                 app.run_task(async {
@@ -267,6 +270,7 @@ fn fallback_swap() {
         rmv_file_assert(&fallback_cfg);
 
         let mut app = APP.defaults().run_headless(false);
+        zng::app::test_log();
         CONFIG.load(JsonConfig::sync(&fallback_cfg));
         CONFIG.get("key", || Txt::from_static("default/fallback")).set("fallback").unwrap();
 
@@ -295,6 +299,7 @@ fn fallback_swap() {
 
     // test
     let mut app = APP.defaults().run_headless(false);
+    zng::app::test_log();
 
     CONFIG.load(FallbackConfig::new(JsonConfig::sync(&main_cfg), JsonConfig::sync(fallback_cfg)));
     app.run_task(async {
@@ -337,6 +342,7 @@ fn fallback_reset() {
         rmv_file_assert(&fallback_cfg);
 
         let mut app = APP.defaults().run_headless(false);
+        zng::app::test_log();
         CONFIG.load(JsonConfig::sync(&fallback_cfg));
         CONFIG.get("key", || Txt::from_static("default/fallback")).set("fallback").unwrap();
 
@@ -365,6 +371,7 @@ fn fallback_reset() {
 
     // test
     let mut app = APP.defaults().run_headless(false);
+    zng::app::test_log();
 
     CONFIG.load(FallbackConfig::new(JsonConfig::sync(&main_cfg), JsonConfig::sync(&fallback_cfg)));
     app.run_task(async {
@@ -409,6 +416,7 @@ fn fallback_reset_entry() {
         rmv_file_assert(&fallback_cfg);
 
         let mut app = APP.defaults().run_headless(false);
+        zng::app::test_log();
         CONFIG.load(JsonConfig::sync(&fallback_cfg));
         CONFIG.get("key", || Txt::from_static("default/fallback")).set("fallback").unwrap();
 
@@ -437,6 +445,7 @@ fn fallback_reset_entry() {
 
     // test
     let mut app = APP.defaults().run_headless(false);
+    zng::app::test_log();
 
     let mut cfg = FallbackConfig::new(JsonConfig::sync(&main_cfg), JsonConfig::sync(&fallback_cfg));
     // wait_idle