#![cfg(feature = "ksm")] use std::io::{Read, Write}; use std::path::PathBuf; use kerbalobjects::ksm::sections::{ArgumentSection, DebugSection}; use kerbalobjects::{ ksm::{ sections::{CodeSection, CodeType, DebugEntry, DebugRange}, Instr, KSMFile, }, BufferIterator, KOSValue, Opcode, }; /// This test is simply a large file that kerbalobjects should be able to read /// correctly. It doesn't yet test the 3 byte argument index size, but it is somewhat /// a stress test. It is provided by the [kosos repository](https://gitlab.com/thexa4/kosos), /// which is a collection of kOS scripts making up "kOS operating system" and a self-hosting compiler. #[test] fn read_kosos_kash() { let mut buffer = Vec::with_capacity(2048); let file_path = PathBuf::from("tests").join("kash.ksm"); let mut file = std::fs::File::open(file_path).expect("Error opening KSM file"); file.read_to_end(&mut buffer) .expect("Error reading kash.ksm"); let mut buffer_iter = BufferIterator::new(&buffer); let expected_args = vec![ KOSValue::String("@0001".into()), KOSValue::Int16(1), KOSValue::Int16(0), KOSValue::StringValue("kpp 1.1".into()), KOSValue::StringValue("https://gitlab.com/thexa4/kos-kpp".into()), KOSValue::String("$class".into()), KOSValue::String("__new".into()), KOSValue::ArgMarker, KOSValue::String("@0481".into()), KOSValue::Int16(2), KOSValue::String("$r".into()), KOSValue::String("@0063".into()), KOSValue::Int16(3), ]; let ksm = KSMFile::parse(&mut buffer_iter).expect("Error reading KSM file"); let mut arg_section_args = ksm.arg_section.arguments(); for arg in expected_args { assert_eq!(&arg, arg_section_args.next().unwrap()); } let mut code_sections = ksm.code_sections(); code_sections.next().unwrap(); code_sections.next().unwrap(); let main_code = code_sections.next().unwrap(); assert!(code_sections.next().is_none()); let expected_instrs = vec![ Opcode::Lbrt, Opcode::Bscp, Opcode::Argb, Opcode::Push, Opcode::Pop, Opcode::Push, Opcode::Pop, Opcode::Push, Opcode::Gmet, Opcode::Push, Opcode::Push, Opcode::Jmp, Opcode::Bscp, Opcode::Stol, Opcode::Argb, Opcode::Push, ]; let mut instructions = main_code.instructions(); for opcode in expected_instrs { assert_eq!(opcode, instructions.next().unwrap().opcode()); } } #[test] fn read_kos_ksm() { let mut buffer = Vec::with_capacity(2048); let file_path = PathBuf::from("tests").join("example.ksm"); let mut file = std::fs::File::open(file_path).expect("Error opening KSM file"); file.read_to_end(&mut buffer) .expect("Error reading example.ksm"); let mut buffer_iter = BufferIterator::new(&buffer); let _ksm = KSMFile::parse(&mut buffer_iter).expect("Error reading KSM file"); } #[test] fn read_write_ksm() { write_ksm(); read_ksm(); } fn write_ksm() { let print = KOSValue::String(String::from("print()")); let empty = KOSValue::String(String::from("")); let two = KOSValue::ScalarInt(2); let marker = KOSValue::ArgMarker; let first = KOSValue::String(String::from("@0001")); let one = KOSValue::Int16(1); let zero = KOSValue::Int16(0); let mut arg_section = ArgumentSection::new(); let first_index = arg_section.add(first); let print_index = arg_section.add(print); let empty_index = arg_section.add(empty); let two_index = arg_section.add(two); let marker_index = arg_section.add(marker); let one_index = arg_section.add(one); let zero_index = arg_section.add(zero); let push_marker = Instr::OneOp(Opcode::Push, marker_index); let add_instr = Instr::ZeroOp(Opcode::Add); let push_two_instr = Instr::OneOp(Opcode::Push, two_index); let call_print = Instr::TwoOp(Opcode::Call, empty_index, print_index); let lbrt_instr = Instr::OneOp(Opcode::Lbrt, first_index); let begin_scope = Instr::TwoOp(Opcode::Bscp, one_index, zero_index); let pop_instr = Instr::ZeroOp(Opcode::Pop); let end_scope = Instr::OneOp(Opcode::Escp, one_index); let argb_instr = Instr::ZeroOp(Opcode::Argb); let mut main_section = CodeSection::new(CodeType::Main); let init_section = CodeSection::new(CodeType::Initialization); let func_section = CodeSection::new(CodeType::Function); main_section.add(lbrt_instr); main_section.add(begin_scope); main_section.add(argb_instr); main_section.add(push_marker); main_section.add(push_two_instr); main_section.add(push_two_instr); main_section.add(add_instr); main_section.add(call_print); main_section.add(pop_instr); main_section.add(end_scope); let code_sections = vec![func_section, init_section, main_section]; let debug_entry = DebugEntry::new(1).with_range(DebugRange::new(6, 0x18)); let debug_section = DebugSection::new(debug_entry); let mut file_buffer = Vec::with_capacity(2048); let ksm = KSMFile::new_from_parts(arg_section, code_sections, debug_section); ksm.write(&mut file_buffer); let file_path = PathBuf::from("tests").join("test.ksm"); let mut file = std::fs::File::create(file_path).expect("Error opening test.ksm"); file.write_all(file_buffer.as_slice()) .expect("test.ksm could not be written to."); } fn read_ksm() { let mut buffer = Vec::with_capacity(2048); let file_path = PathBuf::from("tests").join("test.ksm"); let mut file = std::fs::File::open(file_path).expect("Error opening test.ksm"); file.read_to_end(&mut buffer) .expect("Error reading test.ksm"); let mut buffer_iter = BufferIterator::new(&buffer); let _ksm = KSMFile::parse(&mut buffer_iter); }