use super::*;
use crate::class_file::{AttributeInfo, ClassFile, ConstantPoolEntry};
use crate::memory::{StackFrame, Value};
#[test]
fn test_invokedynamic_string_concat() {
let mut interp = Interpreter::new();
let mut class = ClassFile {
magic: 0xCAFEBABE,
minor_version: 0,
major_version: 52,
constant_pool: vec![
ConstantPoolEntry::ConstantUtf8 { bytes: vec![] },
ConstantPoolEntry::ConstantUtf8 { bytes: "java/lang/invoke/StringConcatFactory".as_bytes().to_vec() },
ConstantPoolEntry::ConstantClass { name_index: 1 },
ConstantPoolEntry::ConstantUtf8 { bytes: "makeConcatWithConstants".as_bytes().to_vec() },
ConstantPoolEntry::ConstantUtf8 { bytes: "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;".as_bytes().to_vec() },
ConstantPoolEntry::ConstantNameAndType { name_index: 3, descriptor_index: 4 },
ConstantPoolEntry::ConstantMethodref { class_index: 2, name_and_type_index: 5 },
ConstantPoolEntry::ConstantMethodHandle { reference_kind: 6, reference_index: 6 },
ConstantPoolEntry::ConstantUtf8 { bytes: "makeConcat".as_bytes().to_vec() },
ConstantPoolEntry::ConstantUtf8 { bytes: "(Ljava/lang/String;I)Ljava/lang/String;".as_bytes().to_vec() },
ConstantPoolEntry::ConstantNameAndType { name_index: 8, descriptor_index: 9 },
ConstantPoolEntry::ConstantInvokeDynamic { bootstrap_method_attr_index: 0, name_and_type_index: 10 },
ConstantPoolEntry::ConstantUtf8 { bytes: "BootstrapMethods".as_bytes().to_vec() },
ConstantPoolEntry::ConstantUtf8 { bytes: vec![1, b' ', b'p', b'r', b'e', b'f', b'i', b'x', b' ', 1, b' ', b's', b'u', b'f', b'f', b'i', b'x'] },
ConstantPoolEntry::ConstantString { string_index: 13 },
],
access_flags: 0x0021,
this_class: 2,
super_class: 0,
interfaces: vec![],
fields: vec![],
methods: vec![],
attributes: vec![],
};
let mut info = Vec::new();
info.extend_from_slice(&1u16.to_be_bytes()); info.extend_from_slice(&7u16.to_be_bytes()); info.extend_from_slice(&1u16.to_be_bytes()); info.extend_from_slice(&14u16.to_be_bytes());
class.attributes.push(AttributeInfo {
attribute_name_index: 12,
info,
});
let mut frame = StackFrame::new(10, 10, "test".to_string());
let hello_addr = interp.memory.heap.allocate_string("Hello".to_string());
frame.stack.push(Value::Reference(hello_addr));
frame.stack.push(Value::Int(42));
let res = interp.handle_invokedynamic(&class, &mut frame, 11);
assert!(res.is_ok());
let result_val = frame.stack.pop().unwrap();
if let Value::Reference(addr) = result_val {
let obj = interp.memory.heap.get_object(addr).unwrap();
let s = obj.string_data.as_ref().unwrap();
assert_eq!(s, "Hello prefix 42 suffix");
} else {
panic!("Expected Reference result, got {:?}", result_val);
}
}