use crate::e2e::escape::escape_kotlin;
const KOTLIN_STRING_LITERAL_CHUNK_CHARS: usize = 8_000;
pub(super) fn kotlin_string_literal(s: &str) -> String {
let chars: Vec<char> = s.chars().collect();
if chars.len() <= KOTLIN_STRING_LITERAL_CHUNK_CHARS {
return format!("\"{}\"", escape_kotlin(s));
}
let joined = chars
.chunks(KOTLIN_STRING_LITERAL_CHUNK_CHARS)
.map(|chunk| format!("\"{}\"", escape_kotlin(&chunk.iter().collect::<String>())))
.collect::<Vec<_>>()
.join(" + ");
format!("({joined})")
}
pub(super) fn json_to_kotlin(value: &serde_json::Value) -> String {
match value {
serde_json::Value::String(s) => kotlin_string_literal(s),
serde_json::Value::Bool(b) => b.to_string(),
serde_json::Value::Number(n) => {
if n.is_f64() {
let s = n.to_string();
if s.contains('.') || s.contains('e') || s.contains('E') {
s
} else {
format!("{s}.0")
}
} else {
n.to_string()
}
}
serde_json::Value::Null => "null".to_string(),
serde_json::Value::Array(arr) => {
let items: Vec<String> = arr.iter().map(json_to_kotlin).collect();
format!("listOf({})", items.join(", "))
}
serde_json::Value::Object(_) => {
let json_str = serde_json::to_string(value).unwrap_or_default();
kotlin_string_literal(&json_str)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_short_value_stays_a_single_quoted_literal() {
assert_eq!(kotlin_string_literal("hello world"), "\"hello world\"");
}
fn oversized_payload() -> String {
"abcdefghij".repeat(10_000) }
#[test]
fn a_value_over_the_jvm_constant_cap_is_never_a_single_literal_segment() {
let literal = kotlin_string_literal(&oversized_payload());
assert!(
literal.contains(" + "),
"an oversized value must be split into multiple concatenated literals: {literal}"
);
let inner = literal
.strip_prefix('(')
.and_then(|rest| rest.strip_suffix(')'))
.unwrap_or(&literal);
for segment in inner.split(" + ") {
assert!(
segment.len() <= 65_535,
"a single Kotlin string literal segment must never exceed the JVM's 65535-byte \
CONSTANT_Utf8 cap: got {} bytes in {segment:?}",
segment.len()
);
}
}
#[test]
fn an_oversized_literal_is_parenthesized_so_a_caller_can_chain_a_method_onto_it() {
let literal = kotlin_string_literal(&oversized_payload());
assert!(
literal.starts_with('(') && literal.ends_with(')'),
"expected a parenthesized concatenation: {literal}"
);
}
}