Rebrand to Galaxy, major improvements to Bedrock support, still needs some TLC though

This commit is contained in:
Ryan Ward
2026-05-07 11:29:34 -05:00
parent f4e2475c60
commit a41cbd8cc7
2433 changed files with 14208 additions and 9409 deletions
@@ -0,0 +1,745 @@
use super::*;
use toml_edit::Item;
#[test]
fn test_json_to_toml_round_trip_bool() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("true", None);
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item);
assert_eq!(json, Some("true".to_string()));
}
#[test]
fn test_json_to_toml_round_trip_integer() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("42", None);
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item);
assert_eq!(json, Some("42".to_string()));
}
#[test]
fn test_json_to_toml_round_trip_float() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("3.14", None);
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item);
assert_eq!(json, Some("3.14".to_string()));
}
#[test]
fn test_json_to_toml_round_trip_string() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("\"hello\"", None);
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item);
assert_eq!(json, Some("\"hello\"".to_string()));
}
#[test]
fn test_json_to_toml_round_trip_object() {
let input = r#"{"dark":"Phenomenon","light":"Paper"}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
// Objects should become TOML tables, not strings.
assert!(matches!(item, Item::Table(_)));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_json_to_toml_round_trip_null() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("null", None);
assert!(matches!(item, Item::None));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item);
assert_eq!(json, None);
}
#[test]
fn test_json_to_toml_round_trip_array_of_strings() {
let input = r#"["cat","echo","ls"]"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
assert!(matches!(item, Item::Value(toml_edit::Value::Array(_))));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_json_to_toml_round_trip_array_of_objects() {
let input = r#"[{"AnchoredRegex":"^bash$"},{"AnchoredRegex":"^fish$"}]"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
assert!(matches!(item, Item::Value(toml_edit::Value::Array(_))));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_json_to_toml_round_trip_nested_struct() {
let input = r#"{"advanced_mode":false,"global":{"mode":"PreviousDir","custom_dir":""},"split_pane":{"mode":"HomeDir","custom_dir":"/tmp"}}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
assert!(matches!(item, Item::Table(_)));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_json_to_toml_round_trip_object_with_nulls() {
// Null fields should be omitted from the table, so the round-trip
// drops them. Verify that non-null fields survive.
let input = r#"{"keybinding":null,"active_pin_position":"Top","pin_screen":null,"hide_window_when_unfocused":true}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
assert!(matches!(item, Item::Table(_)));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
// Null fields are dropped.
let expected = serde_json::json!({
"active_pin_position": "Top",
"hide_window_when_unfocused": true,
});
assert_eq!(actual, expected);
}
#[test]
fn test_json_to_toml_round_trip_empty_array() {
let input = "[]";
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
assert!(matches!(item, Item::Value(toml_edit::Value::Array(_))));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
assert_eq!(json, "[]");
}
#[test]
fn test_max_table_depth_zero_renders_inline() {
// depth 0 = entire value rendered inline
let input = r#"{"uniform_padding":0.0}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, Some(0));
// Should be an inline Value, not an Item::Table
assert!(matches!(
item,
Item::Value(toml_edit::Value::InlineTable(_))
));
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_max_table_depth_one_renders_top_level_as_table_nested_as_inline() {
// depth 1 = top-level object is a section table, but nested objects are inline
let input = r#"{"active_pin_position":"Top","sizes":{"width":100,"height":50},"enabled":true}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, Some(1));
// Top level should be a table
let table = match &item {
Item::Table(t) => t,
other => panic!("expected Table, got {other:?}"),
};
// Primitive fields should be normal values
assert!(matches!(
table.get("active_pin_position"),
Some(Item::Value(_))
));
assert!(matches!(table.get("enabled"), Some(Item::Value(_))));
// Nested object should be an inline table value, not a sub-table
let sizes = table.get("sizes").expect("sizes should exist");
assert!(
matches!(sizes, Item::Value(toml_edit::Value::InlineTable(_))),
"nested object at depth 1 should be inline, got {sizes:?}"
);
// Round-trip the JSON
let json = TomlBackedUserPreferences::toml_item_to_json_string(&item).unwrap();
let expected: serde_json::Value = serde_json::from_str(input).unwrap();
let actual: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_max_table_depth_none_renders_all_as_tables() {
// depth None = unlimited, nested objects become section tables
let input = r#"{"sizes":{"width":100,"height":50}}"#;
let item = TomlBackedUserPreferences::json_value_to_toml_item(input, None);
let table = match &item {
Item::Table(t) => t,
other => panic!("expected Table, got {other:?}"),
};
// Nested object should be a sub-table, not inline
assert!(
matches!(table.get("sizes"), Some(Item::Table(_))),
"nested object with None depth should be a section table"
);
}
#[test]
fn test_write_and_read_with_hierarchy() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
prefs
.write_value_with_hierarchy("font_name", "\"Hack\"".to_string(), Some("font"), None)
.unwrap();
prefs
.write_value_with_hierarchy("font_size", "13.0".to_string(), Some("font"), None)
.unwrap();
prefs
.write_value_with_hierarchy(
"use_thin_strokes",
"true".to_string(),
Some("font.display"),
None,
)
.unwrap();
// Read back
let font_name = prefs
.read_value_with_hierarchy("font_name", Some("font"))
.unwrap();
assert_eq!(font_name, Some("\"Hack\"".to_string()));
let font_size = prefs
.read_value_with_hierarchy("font_size", Some("font"))
.unwrap();
assert_eq!(font_size, Some("13.0".to_string()));
let thin_strokes = prefs
.read_value_with_hierarchy("use_thin_strokes", Some("font.display"))
.unwrap();
assert_eq!(thin_strokes, Some("true".to_string()));
// Verify the TOML file structure
let contents = std::fs::read_to_string(&file_path).unwrap();
assert!(contents.contains("[font]"));
assert!(contents.contains("font_name"));
assert!(contents.contains("font_size"));
assert!(contents.contains("[font.display]"));
assert!(contents.contains("use_thin_strokes"));
}
#[test]
fn test_write_and_read_struct_value() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
// Write a struct value (JSON object) under a hierarchy.
let struct_json = r#"{"left_alt":false,"right_alt":true}"#;
prefs
.write_value_with_hierarchy(
"extra_meta_keys",
struct_json.to_string(),
Some("keys"),
None,
)
.unwrap();
// Read back — should produce equivalent JSON.
let read_back = prefs
.read_value_with_hierarchy("extra_meta_keys", Some("keys"))
.unwrap()
.unwrap();
let expected: serde_json::Value = serde_json::from_str(struct_json).unwrap();
let actual: serde_json::Value = serde_json::from_str(&read_back).unwrap();
assert_eq!(actual, expected);
// Verify the TOML file uses a sub-table, not a JSON string.
let contents = std::fs::read_to_string(&file_path).unwrap();
assert!(contents.contains("[keys.extra_meta_keys]"));
assert!(contents.contains("left_alt = false"));
assert!(contents.contains("right_alt = true"));
// Should NOT contain a JSON blob.
assert!(!contents.contains(r#"{"left_alt"#));
}
#[test]
fn test_new_with_invalid_toml_returns_error_and_recovers_on_reload() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("broken_settings.toml");
// Write invalid TOML to the file.
std::fs::write(&file_path, "this is [not valid toml =").unwrap();
// new() should succeed with an empty document and return the parse error.
let (prefs, parse_error) = TomlBackedUserPreferences::new(file_path.clone());
assert!(
parse_error.is_some(),
"expected a parse error for invalid TOML"
);
// The preferences should behave as empty — no values present.
assert_eq!(
prefs
.read_value_with_hierarchy("font_name", Some("font"))
.unwrap(),
None
);
// is_settings_file should still return true.
assert!(prefs.is_settings_file());
// Now fix the file with valid TOML.
std::fs::write(&file_path, "[font]\nfont_name = \"Hack\"\n").unwrap();
// reload_from_disk should succeed and pick up the new value.
assert!(prefs.reload_from_disk().is_ok());
assert_eq!(
prefs
.read_value_with_hierarchy("font_name", Some("font"))
.unwrap(),
Some("\"Hack\"".to_string())
);
}
#[test]
fn test_writes_inhibited_when_file_initially_broken() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("broken_settings.toml");
let original_content = "this is [not valid toml =";
std::fs::write(&file_path, original_content).unwrap();
let (prefs, parse_error) = TomlBackedUserPreferences::new(file_path.clone());
assert!(parse_error.is_some());
// Writing a setting should succeed in-memory but NOT overwrite the file.
prefs
.write_value_with_hierarchy("font_name", "\"Hack\"".to_string(), Some("font"), None)
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
assert_eq!(
on_disk, original_content,
"broken file should not be overwritten by writes during inhibited state"
);
// Fix the file and reload.
std::fs::write(&file_path, "# now valid\n").unwrap();
assert!(prefs.reload_from_disk().is_ok());
// After reload, writes should flush to disk again.
prefs
.write_value_with_hierarchy("font_name", "\"Hack\"".to_string(), Some("font"), None)
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
assert!(
on_disk.contains("font_name"),
"writes should flush to disk after successful reload"
);
}
#[test]
fn test_string_value_for_numeric_setting_reads_as_json_string() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
// Write a TOML file where font_size is a string instead of a number.
std::fs::write(&file_path, "[font]\nfont_size = \"not_a_number\"\n").unwrap();
let (prefs, parse_error) = TomlBackedUserPreferences::new(file_path);
assert!(
parse_error.is_none(),
"valid TOML should parse without error"
);
// Read the value — should return the JSON-encoded string.
let value = prefs
.read_value_with_hierarchy("font_size", Some("font"))
.unwrap();
// The TOML string "not_a_number" should be JSON-encoded as "\"not_a_number\""
assert_eq!(
value,
Some("\"not_a_number\"".to_string()),
"TOML string should be JSON-encoded"
);
// Attempting to deserialize as f32 should fail.
let result = serde_json::from_str::<f32>(value.as_deref().unwrap());
assert!(result.is_err(), "JSON string should not deserialize as f32");
}
#[test]
fn test_remove_with_hierarchy() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
let (prefs, _) = TomlBackedUserPreferences::new(file_path);
prefs
.write_value_with_hierarchy("font_name", "\"Hack\"".to_string(), Some("font"), None)
.unwrap();
let val = prefs
.read_value_with_hierarchy("font_name", Some("font"))
.unwrap();
assert!(val.is_some());
prefs
.remove_value_with_hierarchy("font_name", Some("font"))
.unwrap();
let val = prefs
.read_value_with_hierarchy("font_name", Some("font"))
.unwrap();
assert!(val.is_none());
}
#[test]
fn test_per_key_write_inhibition_preserves_value_in_file() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
// Write a file with one valid and one "invalid" setting (the TOML itself
// is fine, but the caller decides the value is wrong for the type).
std::fs::write(
&file_path,
"[font]\nfont_size = \"abc\"\nfont_name = \"Hack\"\n",
)
.unwrap();
let (prefs, parse_error) = TomlBackedUserPreferences::new(file_path.clone());
assert!(parse_error.is_none(), "TOML itself is valid");
// Simulate the settings layer detecting the bad value.
prefs.inhibit_writes_for_key("font_size", Some("font"));
// Writing to the inhibited key should be a no-op.
prefs
.write_value_with_hierarchy("font_size", "13.0".to_string(), Some("font"), None)
.unwrap();
// Writing to the NON-inhibited key should succeed.
prefs
.write_value_with_hierarchy("font_name", "\"Fira Code\"".to_string(), Some("font"), None)
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
// The inhibited key's original value must still be present.
assert!(
on_disk.contains("font_size = \"abc\""),
"inhibited key's original value should be preserved, got: {on_disk}"
);
// The non-inhibited key's new value should be written.
assert!(
on_disk.contains("Fira Code"),
"non-inhibited key should be updated, got: {on_disk}"
);
}
#[test]
fn test_per_key_write_inhibition_blocks_remove() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
std::fs::write(&file_path, "[font]\nfont_size = \"abc\"\n").unwrap();
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
prefs.inhibit_writes_for_key("font_size", Some("font"));
// Removing the inhibited key should be a no-op.
prefs
.remove_value_with_hierarchy("font_size", Some("font"))
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
assert!(
on_disk.contains("font_size = \"abc\""),
"inhibited key should not be removed, got: {on_disk}"
);
}
#[test]
fn test_reload_clears_per_key_inhibitions() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
std::fs::write(&file_path, "[font]\nfont_size = \"abc\"\n").unwrap();
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
prefs.inhibit_writes_for_key("font_size", Some("font"));
// Fix the file.
std::fs::write(&file_path, "[font]\nfont_size = 14.0\n").unwrap();
prefs.reload_from_disk().unwrap();
// After reload, the inhibition is cleared — writes should work.
prefs
.write_value_with_hierarchy("font_size", "16.0".to_string(), Some("font"), None)
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
assert!(
on_disk.contains("16.0") || on_disk.contains("16"),
"write should succeed after reload cleared inhibition, got: {on_disk}"
);
}
#[test]
fn test_clear_all_write_inhibitions() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
std::fs::write(&file_path, "[font]\nfont_size = \"abc\"\nfont_name = 123\n").unwrap();
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
prefs.inhibit_writes_for_key("font_size", Some("font"));
prefs.inhibit_writes_for_key("font_name", Some("font"));
prefs.clear_all_write_inhibitions();
// Both keys should now be writable.
prefs
.write_value_with_hierarchy("font_size", "14.0".to_string(), Some("font"), None)
.unwrap();
prefs
.write_value_with_hierarchy("font_name", "\"Hack\"".to_string(), Some("font"), None)
.unwrap();
let on_disk = std::fs::read_to_string(&file_path).unwrap();
assert!(
on_disk.contains("14") && on_disk.contains("Hack"),
"both keys should be writable after clearing all inhibitions, got: {on_disk}"
);
}
#[test]
fn test_file_content_hash_returns_none_for_missing_file() {
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("does_not_exist.toml");
assert_eq!(
None,
TomlBackedUserPreferences::file_content_hash(&file_path)
);
}
#[test]
fn test_file_content_hash_returns_none_for_empty_file() {
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("empty.toml");
std::fs::write(&file_path, "").unwrap();
assert_eq!(
None,
TomlBackedUserPreferences::file_content_hash(&file_path)
);
}
#[test]
fn test_file_content_hash_returns_none_for_whitespace_only_file() {
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("whitespace.toml");
std::fs::write(&file_path, " \n\t \n").unwrap();
assert_eq!(
None,
TomlBackedUserPreferences::file_content_hash(&file_path)
);
}
#[test]
fn test_file_content_hash_is_deterministic_for_identical_content() {
let dir = tempfile::tempdir().unwrap();
let path_a = dir.path().join("a.toml");
let path_b = dir.path().join("b.toml");
let contents = "[font]\nfont_size = 14.0\n";
std::fs::write(&path_a, contents).unwrap();
std::fs::write(&path_b, contents).unwrap();
let hash_a = TomlBackedUserPreferences::file_content_hash(&path_a);
let hash_b = TomlBackedUserPreferences::file_content_hash(&path_b);
assert!(hash_a.is_some());
assert_eq!(hash_a, hash_b);
}
#[test]
fn test_file_content_hash_differs_for_different_content() {
let dir = tempfile::tempdir().unwrap();
let path_a = dir.path().join("a.toml");
let path_b = dir.path().join("b.toml");
std::fs::write(&path_a, "[font]\nfont_size = 14.0\n").unwrap();
std::fs::write(&path_b, "[font]\nfont_size = 18.0\n").unwrap();
let hash_a = TomlBackedUserPreferences::file_content_hash(&path_a);
let hash_b = TomlBackedUserPreferences::file_content_hash(&path_b);
assert!(hash_a.is_some());
assert!(hash_b.is_some());
assert_ne!(hash_a, hash_b);
}
// Pretty-printing tests: verify that wide inline containers get broken
// across lines and that short ones stay on a single line. These drive the
// `prettify_item` pass in `toml_backed.rs`.
/// Writes `value_json` under the given hierarchy + key and returns the full
/// file contents. Also asserts the round-trip (read back as JSON matches).
fn write_and_read_file(
hierarchy: Option<&str>,
key: &str,
value_json: &str,
max_table_depth: Option<u32>,
) -> String {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
let (prefs, _) = TomlBackedUserPreferences::new(file_path.clone());
prefs
.write_value_with_hierarchy(key, value_json.to_string(), hierarchy, max_table_depth)
.unwrap();
// Round-trip: reading back should yield the same JSON value.
let read_back = prefs
.read_value_with_hierarchy(key, hierarchy)
.unwrap()
.expect("value was just written");
let expected: serde_json::Value = serde_json::from_str(value_json).unwrap();
let actual: serde_json::Value = serde_json::from_str(&read_back).unwrap();
assert_eq!(actual, expected, "round-trip should preserve the value");
std::fs::read_to_string(&file_path).unwrap()
}
#[test]
fn test_pretty_print_wide_array_of_inline_tables() {
// Shaped like `custom_secret_regex_list`: each inline table has a
// short field count but the whole array is very wide.
let json = r#"[
{"name":"IPv4 Address","pattern":"\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b"},
{"name":"OpenAI API Key","pattern":"\\bsk-[a-zA-Z0-9]{48}\\b"},
{"name":"GitHub Token","pattern":"\\bghp_[A-Za-z0-9_]{36}\\b"}
]"#;
let contents = write_and_read_file(Some("privacy"), "custom_secret_regex_list", json, None);
// Expect each inline table on its own indented line, with the closing
// bracket on a fresh line.
assert!(
contents.contains("custom_secret_regex_list = [\n"),
"array should open with a newline, got:\n{contents}"
);
assert!(
contents.contains("\n { name = \"IPv4 Address\""),
"each inline table should start on a new indented line, got:\n{contents}"
);
assert!(
contents.contains("\n]\n") || contents.ends_with("\n]"),
"closing bracket should be on its own line, got:\n{contents}"
);
// Each inline table itself is short (2 fields, fits well under
// MAX_INLINE_WIDTH), so it should still be on a single line.
assert!(
!contents.contains("{ name =\n") && !contents.contains("{\n name"),
"individual inline tables should stay on one line, got:\n{contents}"
);
}
#[test]
fn test_pretty_print_short_primitive_array_stays_inline() {
let json = r#"["cat","echo","ls"]"#;
let contents = write_and_read_file(Some("terminal"), "allowed_commands", json, None);
// The whole thing fits on one line; it should stay inline.
assert!(
contents.contains("allowed_commands = [\"cat\", \"echo\", \"ls\"]"),
"short primitive array should stay inline, got:\n{contents}"
);
assert!(
!contents.contains("allowed_commands = [\n"),
"short primitive array should not be broken, got:\n{contents}"
);
}
#[test]
fn test_pretty_print_long_primitive_array_goes_multiline() {
// Construct a primitive array whose single-line rendering clearly
// exceeds `MAX_INLINE_WIDTH`.
let items: Vec<String> = (0..20)
.map(|i| format!("\"/some/fairly/long/path/entry/number/{i}\""))
.collect();
let json = format!("[{}]", items.join(","));
let contents = write_and_read_file(Some("agents"), "allowlist", &json, None);
assert!(
contents.contains("allowlist = [\n"),
"long primitive array should open multi-line, got:\n{contents}"
);
// Each element should sit on its own indented line.
assert!(
contents.contains("\n \"/some/fairly/long/path/entry/number/0\","),
"first element should be on its own indented line with trailing comma, got:\n{contents}"
);
}
#[test]
fn test_pretty_print_short_inline_table_stays_inline() {
// Force inline via max_table_depth = 0 and verify it stays on one line.
let json = r#"{"a":1,"b":2}"#;
let contents = write_and_read_file(Some("section"), "small", json, Some(0));
assert!(
contents.contains("small = { a = 1, b = 2 }"),
"short inline table should stay on one line, got:\n{contents}"
);
}
#[test]
fn test_pretty_print_wide_inline_table_goes_multiline() {
// Force inline via max_table_depth = 0, with many long-valued fields so
// the single-line rendering is wider than `MAX_INLINE_WIDTH`.
let json = concat!(
"{",
"\"first\":\"a string value that is long enough\",",
"\"second\":\"another string value that is long enough\",",
"\"third\":\"one more string value that is long enough\"",
"}"
);
let contents = write_and_read_file(Some("section"), "big", json, Some(0));
assert!(
contents.contains("big = {\n"),
"wide inline table should open multi-line, got:\n{contents}"
);
// Each field should sit on its own indented line.
assert!(
contents.contains("\n first = "),
"first field should be on its own indented line, got:\n{contents}"
);
assert!(
contents.contains("\n second = "),
"second field should be on its own indented line, got:\n{contents}"
);
}
#[test]
fn test_pretty_print_propagates_to_parent_array() {
// A short outer array (one element) containing a wide inline table.
// The inline table must go multi-line (width rule), and that forces
// the array multi-line too (propagation rule) — otherwise we'd render
// something ugly like `[{\n ...\n}]`.
let json = concat!(
"[{",
"\"first\":\"a string value that is long enough\",",
"\"second\":\"another string value that is long enough\",",
"\"third\":\"one more string value that is long enough\"",
"}]"
);
let contents = write_and_read_file(Some("section"), "items", json, None);
assert!(
contents.contains("items = [\n"),
"array should be multi-line because its child is multi-line, got:\n{contents}"
);
assert!(
contents.contains("{\n"),
"inline table should be multi-line, got:\n{contents}"
);
}