bind/interpreter/
decode_bind_rules.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::bytecode_constants::*;
6use crate::interpreter::common::*;
7use crate::interpreter::instruction_decoder::*;
8use num_traits::FromPrimitive;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12// Each node section header contains a u8 node type and a uint32 section
13// size.
14pub const NODE_TYPE_HEADER_SZ: usize = 9;
15
16// At minimum, the bytecode would contain the bind header, symbol table
17// header and instruction header.
18const MINIMUM_BYTECODE_SZ: usize = HEADER_SZ * 3;
19
20// Each debug flag byte contains 1 byte
21const DEBUG_FLAG_SZ: usize = 1;
22
23// Parse through the bytecode and separate out the symbol table, instructions
24// and an optional debug section. Verify the bytecode header and the symbol table
25// header.
26fn get_symbol_table_and_instruction_debug_bytecode(
27    bytecode: Vec<u8>,
28) -> Result<(HashMap<u32, String>, Vec<u8>, Option<Vec<u8>>), BytecodeError> {
29    if bytecode.len() < MINIMUM_BYTECODE_SZ {
30        return Err(BytecodeError::UnexpectedEnd);
31    }
32
33    // Remove the bytecode header and verify the bytecode version.
34    let (version, bytecode) = read_and_remove_header(bytecode, BIND_MAGIC_NUM)?;
35    if version != BYTECODE_VERSION {
36        return Err(BytecodeError::InvalidVersion(version));
37    }
38
39    // Remove the enable_debug flag byte from the bytecode
40    let (debug_flag_byte, bytecode) = read_and_remove_debug_flag(bytecode)?;
41
42    // Remove the symbol table header and verify that the size is less than
43    // the remaining bytecode.
44    let (symbol_table_sz, mut symbol_table_bytecode) =
45        read_and_remove_header(bytecode, SYMB_MAGIC_NUM)?;
46    if symbol_table_bytecode.len() < symbol_table_sz as usize + HEADER_SZ {
47        return Err(BytecodeError::IncorrectSectionSize);
48    }
49
50    // Split the instruction bytecode from the symbol table bytecode.
51    let mut inst_bytecode = symbol_table_bytecode.split_off(symbol_table_sz as usize);
52
53    // Read in the instruction section size and verify that the size is correct.
54    let inst_bytecode_size = u32::from_le_bytes(get_u32_bytes(&inst_bytecode, 4)?);
55    if inst_bytecode.len() < inst_bytecode_size as usize + HEADER_SZ {
56        return Err(BytecodeError::IncorrectSectionSize);
57    }
58
59    // Split the debug bytecode from the instruction bytecode if the debug flag
60    // byte is true.
61    let debug_bytecode = if debug_flag_byte == BYTECODE_ENABLE_DEBUG {
62        let debug_result = inst_bytecode.split_off(inst_bytecode_size as usize + HEADER_SZ);
63        let (debug_sz, debug_result_vec) = read_and_remove_header(debug_result, DEBG_MAGIC_NUM)?;
64        if debug_result_vec.len() != debug_sz as usize {
65            return Err(BytecodeError::IncorrectSectionSize);
66        }
67        Some(debug_result_vec)
68    } else {
69        None
70    };
71
72    Ok((read_symbol_table(symbol_table_bytecode)?, inst_bytecode, debug_bytecode))
73}
74
75// Remove the instructions in the first node and return it along with the
76// remaining bytecode.
77fn split_off_node(
78    mut bytecode: Vec<u8>,
79    expect_primary: bool,
80    symbol_table: &HashMap<u32, String>,
81) -> Result<(bool, Node, Vec<u8>), BytecodeError> {
82    // Verify the node type and retrieve the node section size.
83    let (is_optional, node_id, node_inst_sz) =
84        verify_and_read_node_header(&bytecode, expect_primary)?;
85    if bytecode.len() < NODE_TYPE_HEADER_SZ + node_inst_sz as usize {
86        return Err(BytecodeError::IncorrectNodeSectionSize);
87    }
88
89    if !symbol_table.contains_key(&node_id) {
90        return Err(BytecodeError::MissingNodeIdInSymbolTable);
91    }
92
93    let mut node_instructions = bytecode.split_off(NODE_TYPE_HEADER_SZ);
94    let remaining_bytecode = node_instructions.split_off(node_inst_sz as usize);
95    let decoded_instructions =
96        InstructionDecoder::new(symbol_table, &node_instructions).decode()?;
97    Ok((
98        is_optional,
99        Node {
100            name_id: node_id,
101            instructions: node_instructions,
102            decoded_instructions: decoded_instructions,
103        },
104        remaining_bytecode,
105    ))
106}
107
108#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
109pub enum DecodedRules {
110    Normal(DecodedBindRules),
111    Composite(DecodedCompositeBindRules),
112}
113
114impl DecodedRules {
115    pub fn new(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
116        let (symbol_table, inst_bytecode, debug_bytecode) =
117            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
118        let parsed_magic_num = u32::from_be_bytes(get_u32_bytes(&inst_bytecode, 0)?);
119        if parsed_magic_num == COMPOSITE_MAGIC_NUM {
120            return Ok(DecodedRules::Composite(DecodedCompositeBindRules::new(
121                symbol_table,
122                inst_bytecode,
123                decode_debug_bytecode(debug_bytecode)?,
124            )?));
125        }
126        Ok(DecodedRules::Normal(DecodedBindRules::new(
127            symbol_table,
128            inst_bytecode,
129            decode_debug_bytecode(debug_bytecode)?,
130        )?))
131    }
132}
133
134#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
135pub struct DecodedDebugInfo {
136    pub symbol_table: HashMap<u32, String>,
137}
138
139impl DecodedDebugInfo {
140    pub fn new(debug_bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
141        // Verify the debug symbol table header and size.
142        let (debug_sz, debug_sym_bytecode) =
143            read_and_remove_header(debug_bytecode, DBSY_MAGIC_NUM)?;
144        if debug_sym_bytecode.len() != debug_sz as usize {
145            return Err(BytecodeError::IncorrectSectionSize);
146        }
147        // Read in the debug symbol table.
148        let symbol_table = read_symbol_table(debug_sym_bytecode)?;
149
150        Ok(DecodedDebugInfo { symbol_table: symbol_table })
151    }
152}
153
154// Decode the debug bytecode if it's not empty.
155pub fn decode_debug_bytecode(
156    debug_bytecode: Option<Vec<u8>>,
157) -> Result<Option<DecodedDebugInfo>, BytecodeError> {
158    if debug_bytecode.is_none() {
159        return Ok(None);
160    }
161    let bytecode = debug_bytecode.unwrap();
162    if bytecode.is_empty() {
163        return Ok(None);
164    }
165    return Ok(Some(DecodedDebugInfo::new(bytecode)?));
166}
167
168// This struct decodes and unwraps the given bytecode into a symbol table
169// and list of instructions. It contains an optional debug section.
170#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
171pub struct DecodedBindRules {
172    pub symbol_table: HashMap<u32, String>,
173    pub instructions: Vec<u8>,
174    pub decoded_instructions: Vec<DecodedInstruction>,
175    pub debug_info: Option<DecodedDebugInfo>,
176}
177
178impl DecodedBindRules {
179    pub fn new(
180        symbol_table: HashMap<u32, String>,
181        inst_bytecode: Vec<u8>,
182        debug_info: Option<DecodedDebugInfo>,
183    ) -> Result<Self, BytecodeError> {
184        // Remove the INST header and check if the section size is correct.
185        let (inst_sz, inst_bytecode) =
186            read_and_remove_header(inst_bytecode, INSTRUCTION_MAGIC_NUM)?;
187
188        if inst_bytecode.len() != inst_sz as usize {
189            return Err(BytecodeError::IncorrectSectionSize);
190        }
191
192        let decoded_instructions =
193            InstructionDecoder::new(&symbol_table, &inst_bytecode).decode()?;
194
195        Ok(DecodedBindRules {
196            symbol_table: symbol_table,
197            instructions: inst_bytecode,
198            decoded_instructions: decoded_instructions,
199            debug_info: debug_info,
200        })
201    }
202
203    pub fn from_bytecode(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
204        let (symbol_table, inst_bytecode, debug_bytecode) =
205            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
206        DecodedBindRules::new(symbol_table, inst_bytecode, decode_debug_bytecode(debug_bytecode)?)
207    }
208}
209
210#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
211pub struct Node {
212    // Symbol table ID for the node name.
213    pub name_id: u32,
214    pub instructions: Vec<u8>,
215    pub decoded_instructions: Vec<DecodedInstruction>,
216}
217
218// This struct decodes and unwraps the given bytecode into a symbol table
219// and list of instructions.
220#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
221pub struct DecodedCompositeBindRules {
222    pub symbol_table: HashMap<u32, String>,
223    pub device_name_id: u32,
224    pub primary_node: Node,
225    pub additional_nodes: Vec<Node>,
226    pub optional_nodes: Vec<Node>,
227    pub debug_info: Option<DecodedDebugInfo>,
228}
229
230impl DecodedCompositeBindRules {
231    pub fn new(
232        symbol_table: HashMap<u32, String>,
233        composite_inst_bytecode: Vec<u8>,
234        debug_info: Option<DecodedDebugInfo>,
235    ) -> Result<Self, BytecodeError> {
236        // Separate the instruction bytecode out of the symbol table bytecode and verify
237        // the magic number and length. Remove the composite instruction header.
238        let (composite_inst_sz, mut composite_inst_bytecode) =
239            read_and_remove_header(composite_inst_bytecode, COMPOSITE_MAGIC_NUM)?;
240        if composite_inst_bytecode.len() != composite_inst_sz as usize {
241            return Err(BytecodeError::IncorrectSectionSize);
242        }
243
244        // Retrieve the device name ID and check if it's in the symbol table.
245        let device_name_id = u32::from_le_bytes(get_u32_bytes(&composite_inst_bytecode, 0)?);
246        if !symbol_table.contains_key(&device_name_id) {
247            return Err(BytecodeError::MissingDeviceNameInSymbolTable);
248        }
249
250        // Split off the device name ID.
251        let node_bytecode = composite_inst_bytecode.split_off(4);
252
253        // Extract the primary node instructions.
254        let (_, primary_node, mut node_bytecode) =
255            split_off_node(node_bytecode, true, &symbol_table)?;
256
257        // Extract additional and optional nodes from the remaining bytecode until there's none left.
258        let mut additional_nodes: Vec<Node> = vec![];
259        let mut optional_nodes: Vec<Node> = vec![];
260        while !node_bytecode.is_empty() {
261            let (is_optional, node, remaining) =
262                split_off_node(node_bytecode, false, &symbol_table)?;
263            node_bytecode = remaining;
264            if is_optional {
265                optional_nodes.push(node);
266            } else {
267                additional_nodes.push(node);
268            }
269        }
270
271        Ok(DecodedCompositeBindRules {
272            symbol_table: symbol_table,
273            device_name_id: device_name_id,
274            primary_node: primary_node,
275            additional_nodes: additional_nodes,
276            optional_nodes: optional_nodes,
277            debug_info: debug_info,
278        })
279    }
280
281    pub fn from_bytecode(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
282        let (symbol_table, inst_bytecode, debug_bytecode) =
283            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
284        DecodedCompositeBindRules::new(
285            symbol_table,
286            inst_bytecode,
287            decode_debug_bytecode(debug_bytecode)?,
288        )
289    }
290}
291
292fn get_u32_bytes(bytecode: &Vec<u8>, idx: usize) -> Result<[u8; 4], BytecodeError> {
293    if idx + 4 > bytecode.len() {
294        return Err(BytecodeError::UnexpectedEnd);
295    }
296
297    let mut bytes: [u8; 4] = [0; 4];
298    bytes.copy_from_slice(&bytecode[idx..(4 + idx)]);
299    Ok(bytes)
300}
301
302// Verify the header magic number. Return the value after the magic number and the following bytes.
303fn read_and_remove_header(
304    mut bytecode: Vec<u8>,
305    magic_num: u32,
306) -> Result<(u32, Vec<u8>), BytecodeError> {
307    let parsed_magic_num = u32::from_be_bytes(get_u32_bytes(&bytecode, 0)?);
308    if parsed_magic_num != magic_num {
309        return Err(BytecodeError::InvalidHeader(magic_num, parsed_magic_num));
310    }
311
312    let val = u32::from_le_bytes(get_u32_bytes(&bytecode, 4)?);
313    Ok((val, bytecode.split_off(HEADER_SZ)))
314}
315
316// Verify the enable_debug flag byte.
317fn read_and_remove_debug_flag(mut bytecode: Vec<u8>) -> Result<(u8, Vec<u8>), BytecodeError> {
318    let debug_flag_byte = bytecode[0];
319    if debug_flag_byte != BYTECODE_DISABLE_DEBUG && debug_flag_byte != BYTECODE_ENABLE_DEBUG {
320        return Err(BytecodeError::InvalidDebugFlag(debug_flag_byte));
321    }
322    Ok((debug_flag_byte, bytecode.split_off(DEBUG_FLAG_SZ)))
323}
324
325// Verify the node type and return the node ID and the number of bytes in the node instructions.
326fn verify_and_read_node_header(
327    bytecode: &Vec<u8>,
328    expect_primary: bool,
329) -> Result<(bool, u32, u32), BytecodeError> {
330    if bytecode.len() < NODE_TYPE_HEADER_SZ {
331        return Err(BytecodeError::UnexpectedEnd);
332    }
333
334    let is_optional = match FromPrimitive::from_u8(bytecode[0]) {
335        Some(RawNodeType::Primary) => {
336            if !expect_primary {
337                return Err(BytecodeError::MultiplePrimaryNodes);
338            }
339
340            false
341        }
342        Some(RawNodeType::Additional) => {
343            if expect_primary {
344                return Err(BytecodeError::InvalidPrimaryNode);
345            }
346
347            false
348        }
349        Some(RawNodeType::Optional) => {
350            if expect_primary {
351                return Err(BytecodeError::InvalidPrimaryNode);
352            }
353
354            true
355        }
356        None => {
357            return Err(BytecodeError::InvalidNodeType(bytecode[0]));
358        }
359    };
360
361    let node_id = u32::from_le_bytes(get_u32_bytes(bytecode, 1)?);
362    let inst_sz = u32::from_le_bytes(get_u32_bytes(bytecode, 5)?);
363    Ok((is_optional, node_id, inst_sz))
364}
365
366fn read_string(iter: &mut BytecodeIter) -> Result<String, BytecodeError> {
367    let mut str_bytes = vec![];
368
369    // Read in the bytes for the string until a zero terminator is reached.
370    // If the number of bytes exceed the maximum string length, return an error.
371    loop {
372        let byte = *next_u8(iter)?;
373        if byte == 0 {
374            break;
375        }
376
377        str_bytes.push(byte);
378        if str_bytes.len() > MAX_STRING_LENGTH {
379            return Err(BytecodeError::InvalidStringLength);
380        }
381    }
382
383    if str_bytes.is_empty() {
384        return Err(BytecodeError::EmptyString);
385    }
386
387    String::from_utf8(str_bytes).map_err(|_| BytecodeError::Utf8ConversionFailure)
388}
389
390fn read_symbol_table(bytecode: Vec<u8>) -> Result<HashMap<u32, String>, BytecodeError> {
391    let mut iter = bytecode.iter();
392
393    let mut symbol_table = HashMap::new();
394    let mut expected_key = SYMB_TBL_START_KEY;
395    while let Some(key) = try_next_u32(&mut iter)? {
396        if key != expected_key {
397            return Err(BytecodeError::InvalidSymbolTableKey(key));
398        }
399
400        // Read the string and increase the byte count by the string length and the
401        // zero terminator.
402        let str_val = read_string(&mut iter)?;
403        symbol_table.insert(key, str_val);
404        expected_key += 1;
405    }
406
407    Ok(symbol_table)
408}
409
410#[cfg(test)]
411mod test {
412    use super::*;
413    use crate::compiler::Symbol;
414    use crate::interpreter::test_common::*;
415    use crate::parser::bind_library;
416
417    fn append_section_header(bytecode: &mut Vec<u8>, magic_num: u32, sz: u32) {
418        bytecode.extend_from_slice(&magic_num.to_be_bytes());
419        bytecode.extend_from_slice(&sz.to_le_bytes());
420    }
421
422    fn append_node_header(bytecode: &mut Vec<u8>, node_type: RawNodeType, node_id: u32, sz: u32) {
423        bytecode.push(node_type as u8);
424        bytecode.extend_from_slice(&node_id.to_le_bytes());
425        bytecode.extend_from_slice(&sz.to_le_bytes());
426    }
427
428    #[test]
429    fn test_invalid_header() {
430        // Test invalid magic number.
431        let mut bytecode: Vec<u8> = vec![0x41, 0x49, 0x4E, 0x44, 0x02, 0, 0, 0];
432        bytecode.push(BYTECODE_DISABLE_DEBUG);
433        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
434        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
435        assert_eq!(
436            Err(BytecodeError::InvalidHeader(BIND_MAGIC_NUM, 0x41494E44)),
437            DecodedRules::new(bytecode)
438        );
439
440        // Test invalid version.
441        let mut bytecode: Vec<u8> = vec![0x42, 0x49, 0x4E, 0x44, 0x03, 0, 0, 0];
442        bytecode.push(BYTECODE_DISABLE_DEBUG);
443        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
444        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
445        assert_eq!(Err(BytecodeError::InvalidVersion(3)), DecodedRules::new(bytecode));
446
447        // Test invalid symbol table header.
448        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
449        bytecode.push(BYTECODE_DISABLE_DEBUG);
450        append_section_header(&mut bytecode, 0xAAAAAAAA, 0);
451        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
452        assert_eq!(
453            Err(BytecodeError::InvalidHeader(SYMB_MAGIC_NUM, 0xAAAAAAAA)),
454            DecodedRules::new(bytecode)
455        );
456
457        // Test invalid instruction header.
458        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
459        bytecode.push(BYTECODE_DISABLE_DEBUG);
460        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
461        append_section_header(&mut bytecode, 0xAAAAAAAA, 0);
462        assert_eq!(
463            Err(BytecodeError::InvalidHeader(INSTRUCTION_MAGIC_NUM, 0xAAAAAAAA)),
464            DecodedRules::new(bytecode)
465        );
466
467        // Test invalid debug information section header.
468        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
469        bytecode.push(BYTECODE_ENABLE_DEBUG);
470        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
471        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
472        append_section_header(&mut bytecode, 0x44454241, 0);
473        assert_eq!(
474            Err(BytecodeError::InvalidHeader(DEBG_MAGIC_NUM, 0x44454241)),
475            DecodedRules::new(bytecode)
476        );
477
478        // Test invalid debug symbol section header.
479        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
480        bytecode.push(BYTECODE_ENABLE_DEBUG);
481        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
482        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
483        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 8);
484        append_section_header(&mut bytecode, 0x44454247, 0);
485        assert_eq!(
486            Err(BytecodeError::InvalidHeader(DBSY_MAGIC_NUM, 0x44454247)),
487            DecodedRules::new(bytecode)
488        );
489    }
490
491    #[test]
492    fn test_long_string() {
493        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
494        bytecode.push(BYTECODE_DISABLE_DEBUG);
495
496        let mut long_str: [u8; 275] = [0x41; 275];
497        long_str[274] = 0;
498
499        let symbol_section_sz = long_str.len() + 4;
500        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, symbol_section_sz as u32);
501
502        bytecode.extend_from_slice(&[1, 0, 0, 0]);
503        bytecode.extend_from_slice(&long_str);
504
505        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
506        assert_eq!(Err(BytecodeError::InvalidStringLength), DecodedRules::new(bytecode));
507    }
508
509    #[test]
510    fn test_unexpected_end() {
511        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
512        bytecode.push(BYTECODE_DISABLE_DEBUG);
513        bytecode.extend_from_slice(&SYMB_MAGIC_NUM.to_be_bytes());
514        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
515    }
516
517    #[test]
518    fn test_string_with_no_zero_terminator() {
519        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
520        bytecode.push(BYTECODE_DISABLE_DEBUG);
521        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 14);
522
523        let invalid_str: [u8; 10] = [0x41; 10];
524        bytecode.extend_from_slice(&[1, 0, 0, 0]);
525        bytecode.extend_from_slice(&invalid_str);
526
527        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
528
529        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
530    }
531
532    #[test]
533    fn test_duplicate_key() {
534        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
535        bytecode.push(BYTECODE_DISABLE_DEBUG);
536        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 14);
537
538        let str_1: [u8; 3] = [0x41, 0x42, 0];
539        bytecode.extend_from_slice(&[1, 0, 0, 0]);
540        bytecode.extend_from_slice(&str_1);
541
542        let str_2: [u8; 3] = [0x42, 0x43, 0];
543        bytecode.extend_from_slice(&[1, 0, 0, 0]);
544        bytecode.extend_from_slice(&str_2);
545
546        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
547        assert_eq!(Err(BytecodeError::InvalidSymbolTableKey(1)), DecodedRules::new(bytecode));
548    }
549
550    #[test]
551    fn test_invalid_key() {
552        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
553        bytecode.push(BYTECODE_DISABLE_DEBUG);
554        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 15);
555
556        let str_1: [u8; 4] = [0x41, 0x45, 0x60, 0];
557        bytecode.extend_from_slice(&[1, 0, 0, 0]);
558        bytecode.extend_from_slice(&str_1);
559
560        let str_2: [u8; 3] = [0x42, 0x43, 0];
561        bytecode.extend_from_slice(&[5, 0, 0, 0]);
562        bytecode.extend_from_slice(&str_2);
563
564        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
565        assert_eq!(Err(BytecodeError::InvalidSymbolTableKey(5)), DecodedRules::new(bytecode));
566    }
567
568    #[test]
569    fn test_cutoff_symbol_table_key() {
570        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
571        bytecode.push(BYTECODE_DISABLE_DEBUG);
572        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
573
574        let str_1: [u8; 3] = [0x41, 0x42, 0];
575        bytecode.extend_from_slice(&[1, 0, 0, 0]);
576        bytecode.extend_from_slice(&str_1);
577
578        bytecode.extend_from_slice(&[2, 0]);
579        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
580
581        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
582    }
583
584    #[test]
585    fn test_incorrect_inst_size() {
586        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
587        bytecode.push(BYTECODE_DISABLE_DEBUG);
588        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
589        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
590        bytecode.push(0x30);
591        assert_eq!(Err(BytecodeError::IncorrectSectionSize), DecodedRules::new(bytecode));
592    }
593
594    #[test]
595    fn test_minimum_size_bytecode() {
596        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
597        bytecode.push(BYTECODE_DISABLE_DEBUG);
598        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
599        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
600        assert_eq!(
601            DecodedRules::Normal(DecodedBindRules {
602                symbol_table: HashMap::new(),
603                instructions: vec![],
604                decoded_instructions: vec![],
605                debug_info: None,
606            }),
607            DecodedRules::new(bytecode).unwrap()
608        );
609    }
610
611    #[test]
612    fn test_incorrect_size_symbol_table() {
613        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
614        bytecode.push(BYTECODE_DISABLE_DEBUG);
615        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, u32::MAX);
616        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
617        assert_eq!(Err(BytecodeError::IncorrectSectionSize), DecodedRules::new(bytecode));
618    }
619
620    #[test]
621    fn test_instructions() {
622        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
623        bytecode.push(BYTECODE_DISABLE_DEBUG);
624        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
625
626        let instructions = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0, 0x10];
627        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
628        bytecode.extend_from_slice(&instructions);
629        let bind_rules = DecodedBindRules::from_bytecode(bytecode).unwrap();
630        assert_eq!(instructions.to_vec(), bind_rules.instructions);
631    }
632
633    #[test]
634    fn test_enable_debug_flag_empty_debug_info_section() {
635        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
636        bytecode.push(BYTECODE_ENABLE_DEBUG);
637        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
638
639        let instructions = [0x30];
640        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
641        bytecode.extend_from_slice(&instructions);
642        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0);
643
644        let rules = DecodedBindRules {
645            symbol_table: HashMap::new(),
646            instructions: vec![0x30],
647            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
648            debug_info: None,
649        };
650
651        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
652    }
653
654    #[test]
655    fn test_enable_debug_flag_empty_debug_symb_section() {
656        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
657        bytecode.push(BYTECODE_ENABLE_DEBUG);
658        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
659
660        let instructions = [0x30];
661        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
662        bytecode.extend_from_slice(&instructions);
663        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 8);
664        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0);
665
666        let rules = DecodedBindRules {
667            symbol_table: HashMap::new(),
668            instructions: vec![0x30],
669            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
670            debug_info: Some(DecodedDebugInfo { symbol_table: HashMap::new() }),
671        };
672
673        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
674    }
675
676    #[test]
677    fn test_enable_debug_flag() {
678        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
679        bytecode.push(BYTECODE_ENABLE_DEBUG);
680        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
681
682        let instructions = [0x30];
683        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
684        bytecode.extend_from_slice(&instructions);
685
686        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
687        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
688
689        let str_1: [u8; 22] = [
690            // "fuchsia.BIND_PROTOCOL"
691            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
692            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
693        ];
694        bytecode.extend_from_slice(&[1, 0, 0, 0]);
695        bytecode.extend_from_slice(&str_1);
696
697        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
698        expected_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
699
700        let rules = DecodedBindRules {
701            symbol_table: HashMap::new(),
702            instructions: vec![0x30],
703            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
704            debug_info: Some(DecodedDebugInfo { symbol_table: expected_symbol_table }),
705        };
706
707        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
708    }
709
710    #[test]
711    fn test_missing_debug_flag() {
712        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
713        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
714
715        let instructions = [0x01, 0x01, 0x05, 0, 0, 0, 0x01, 0x16, 0, 0, 0];
716        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
717        bytecode.extend_from_slice(&instructions);
718
719        assert_eq!(Err(BytecodeError::InvalidDebugFlag(0x53)), DecodedRules::new(bytecode));
720    }
721
722    #[test]
723    fn test_invalid_debug_flag() {
724        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
725        bytecode.push(0x03);
726        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
727
728        let instructions = [0x01, 0x01, 0x05, 0, 0, 0, 0x01, 0x16, 0, 0, 0];
729        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
730        bytecode.extend_from_slice(&instructions);
731
732        assert_eq!(Err(BytecodeError::InvalidDebugFlag(0x03)), DecodedRules::new(bytecode));
733    }
734
735    #[test]
736    fn test_value_key_missing_in_symbols() {
737        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
738        bytecode.push(BYTECODE_DISABLE_DEBUG);
739        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
740
741        let instructions = [0x01, 0x00, 0, 0, 0, 0x05, 0x10, 0, 0, 0, 0];
742        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
743        bytecode.extend_from_slice(&instructions);
744
745        assert_eq!(
746            Err(BytecodeError::MissingEntryInSymbolTable(0x05000000)),
747            DecodedRules::new(bytecode)
748        );
749    }
750
751    #[test]
752    fn test_valid_bytecode() {
753        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
754        bytecode.push(BYTECODE_DISABLE_DEBUG);
755        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
756
757        let str_1: [u8; 5] = [0x57, 0x52, 0x45, 0x4E, 0]; // "WREN"
758        bytecode.extend_from_slice(&[1, 0, 0, 0]);
759        bytecode.extend_from_slice(&str_1);
760
761        let str_2: [u8; 5] = [0x44, 0x55, 0x43, 0x4B, 0]; // "DUCK"
762        bytecode.extend_from_slice(&[2, 0, 0, 0]);
763        bytecode.extend_from_slice(&str_2);
764
765        let instructions = [
766            0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0, 0x10, // 0x05000000 == 0x10000010
767            0x11, 0x01, 0, 0, 0, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0,
768            0, // jmp 1 if 0x05000000 == 0x10
769            0x30, 0x20, // abort, jump pad
770            0x11, 0x01, 0, 0, 0, 0x00, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0,
771            0, // jmp 1 if key("WREN") == "DUCK"
772            0x30, 0x20, // abort, jump pad
773            0x10, 0x02, 0, 0, 0, 0x30, 0x30, 0x20, // jump 2, 2 aborts, jump pad
774        ];
775        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
776        bytecode.extend_from_slice(&instructions);
777
778        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
779        expected_symbol_table.insert(1, "WREN".to_string());
780        expected_symbol_table.insert(2, "DUCK".to_string());
781
782        let expected_decoded_inst = vec![
783            DecodedInstruction::Condition(DecodedCondition {
784                is_equal: true,
785                lhs: Symbol::NumberValue(0x05000000),
786                rhs: Symbol::NumberValue(0x10000010),
787            }),
788            DecodedInstruction::Jump(Some(DecodedCondition {
789                is_equal: true,
790                lhs: Symbol::NumberValue(0x05000000),
791                rhs: Symbol::NumberValue(0x10),
792            })),
793            DecodedInstruction::UnconditionalAbort,
794            DecodedInstruction::Label,
795            DecodedInstruction::Jump(Some(DecodedCondition {
796                is_equal: true,
797                lhs: Symbol::Key("WREN".to_string(), bind_library::ValueType::Str),
798                rhs: Symbol::StringValue("DUCK".to_string()),
799            })),
800            DecodedInstruction::UnconditionalAbort,
801            DecodedInstruction::Label,
802            DecodedInstruction::Jump(None),
803            DecodedInstruction::UnconditionalAbort,
804            DecodedInstruction::UnconditionalAbort,
805            DecodedInstruction::Label,
806        ];
807
808        let rules = DecodedBindRules {
809            symbol_table: expected_symbol_table,
810            instructions: instructions.to_vec(),
811            decoded_instructions: expected_decoded_inst,
812            debug_info: None,
813        };
814        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
815    }
816
817    #[test]
818    fn test_enable_debug_composite() {
819        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
820        bytecode.push(BYTECODE_ENABLE_DEBUG);
821        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
822
823        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
824        bytecode.extend_from_slice(&[1, 0, 0, 0]);
825        bytecode.extend_from_slice(&device_name);
826
827        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
828        bytecode.extend_from_slice(&[2, 0, 0, 0]);
829        bytecode.extend_from_slice(&primary_node_name);
830
831        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
832        bytecode.extend_from_slice(&[3, 0, 0, 0]);
833        bytecode.extend_from_slice(&node_name_1);
834
835        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
836        bytecode.extend_from_slice(&[4, 0, 0, 0]);
837        bytecode.extend_from_slice(&node_name_2);
838
839        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
840        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
841        let additional_node_inst_2 = [0x30, 0x30];
842
843        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
844            + ((NODE_TYPE_HEADER_SZ * 3)
845                + primary_node_inst.len()
846                + additional_node_inst_1.len()
847                + additional_node_inst_2.len()) as u32;
848        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
849
850        // Add device name ID.
851        bytecode.extend_from_slice(&[1, 0, 0, 0]);
852
853        // Add the node instructions.
854        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
855        bytecode.extend_from_slice(&primary_node_inst);
856        append_node_header(
857            &mut bytecode,
858            RawNodeType::Additional,
859            3,
860            additional_node_inst_1.len() as u32,
861        );
862        bytecode.extend_from_slice(&additional_node_inst_1);
863        append_node_header(
864            &mut bytecode,
865            RawNodeType::Additional,
866            4,
867            additional_node_inst_2.len() as u32,
868        );
869        bytecode.extend_from_slice(&additional_node_inst_2);
870
871        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
872        expected_symbol_table.insert(1, "IBIS".to_string());
873        expected_symbol_table.insert(2, "RAIL".to_string());
874        expected_symbol_table.insert(3, "COOT".to_string());
875        expected_symbol_table.insert(4, "PLOVER".to_string());
876
877        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
878        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
879
880        let str_1: [u8; 22] = [
881            // "fuchsia.BIND_PROTOCOL"
882            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
883            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
884        ];
885        bytecode.extend_from_slice(&[1, 0, 0, 0]);
886        bytecode.extend_from_slice(&str_1);
887
888        let mut debug_symbol_table: HashMap<u32, String> = HashMap::new();
889        debug_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
890
891        let rules = DecodedCompositeBindRules {
892            symbol_table: expected_symbol_table,
893            device_name_id: 1,
894            primary_node: Node {
895                name_id: 2,
896                instructions: primary_node_inst.to_vec(),
897                decoded_instructions: vec![
898                    DecodedInstruction::UnconditionalAbort,
899                    DecodedInstruction::Condition(DecodedCondition {
900                        is_equal: true,
901                        lhs: Symbol::NumberValue(0x5000000),
902                        rhs: Symbol::NumberValue(0x200010),
903                    }),
904                ],
905            },
906            additional_nodes: vec![
907                Node {
908                    name_id: 3,
909                    instructions: additional_node_inst_1.to_vec(),
910                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
911                        is_equal: false,
912                        lhs: Symbol::NumberValue(0x2000000),
913                        rhs: Symbol::NumberValue(0x10000000),
914                    })],
915                },
916                Node {
917                    name_id: 4,
918                    instructions: additional_node_inst_2.to_vec(),
919                    decoded_instructions: vec![
920                        DecodedInstruction::UnconditionalAbort,
921                        DecodedInstruction::UnconditionalAbort,
922                    ],
923                },
924            ],
925            optional_nodes: vec![],
926            debug_info: Some(DecodedDebugInfo { symbol_table: debug_symbol_table }),
927        };
928        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
929    }
930
931    #[test]
932    fn test_enable_debug_composite_with_optional() {
933        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
934        bytecode.push(BYTECODE_ENABLE_DEBUG);
935        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
936
937        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
938        bytecode.extend_from_slice(&[1, 0, 0, 0]);
939        bytecode.extend_from_slice(&device_name);
940
941        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
942        bytecode.extend_from_slice(&[2, 0, 0, 0]);
943        bytecode.extend_from_slice(&primary_node_name);
944
945        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
946        bytecode.extend_from_slice(&[3, 0, 0, 0]);
947        bytecode.extend_from_slice(&node_name_1);
948
949        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
950        bytecode.extend_from_slice(&[4, 0, 0, 0]);
951        bytecode.extend_from_slice(&node_name_2);
952
953        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
954        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
955        let optional_node_inst_1 = [0x30, 0x30];
956
957        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
958            + ((NODE_TYPE_HEADER_SZ * 3)
959                + primary_node_inst.len()
960                + additional_node_inst_1.len()
961                + optional_node_inst_1.len()) as u32;
962        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
963
964        // Add device name ID.
965        bytecode.extend_from_slice(&[1, 0, 0, 0]);
966
967        // Add the node instructions.
968        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
969        bytecode.extend_from_slice(&primary_node_inst);
970        append_node_header(
971            &mut bytecode,
972            RawNodeType::Additional,
973            3,
974            additional_node_inst_1.len() as u32,
975        );
976        bytecode.extend_from_slice(&additional_node_inst_1);
977        append_node_header(
978            &mut bytecode,
979            RawNodeType::Optional,
980            4,
981            optional_node_inst_1.len() as u32,
982        );
983        bytecode.extend_from_slice(&optional_node_inst_1);
984
985        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
986        expected_symbol_table.insert(1, "IBIS".to_string());
987        expected_symbol_table.insert(2, "RAIL".to_string());
988        expected_symbol_table.insert(3, "COOT".to_string());
989        expected_symbol_table.insert(4, "PLOVER".to_string());
990
991        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
992        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
993
994        let str_1: [u8; 22] = [
995            // "fuchsia.BIND_PROTOCOL"
996            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
997            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
998        ];
999        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1000        bytecode.extend_from_slice(&str_1);
1001
1002        let mut debug_symbol_table: HashMap<u32, String> = HashMap::new();
1003        debug_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
1004
1005        let rules = DecodedCompositeBindRules {
1006            symbol_table: expected_symbol_table,
1007            device_name_id: 1,
1008            primary_node: Node {
1009                name_id: 2,
1010                instructions: primary_node_inst.to_vec(),
1011                decoded_instructions: vec![
1012                    DecodedInstruction::UnconditionalAbort,
1013                    DecodedInstruction::Condition(DecodedCondition {
1014                        is_equal: true,
1015                        lhs: Symbol::NumberValue(0x5000000),
1016                        rhs: Symbol::NumberValue(0x200010),
1017                    }),
1018                ],
1019            },
1020            additional_nodes: vec![Node {
1021                name_id: 3,
1022                instructions: additional_node_inst_1.to_vec(),
1023                decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1024                    is_equal: false,
1025                    lhs: Symbol::NumberValue(0x2000000),
1026                    rhs: Symbol::NumberValue(0x10000000),
1027                })],
1028            }],
1029            optional_nodes: vec![Node {
1030                name_id: 4,
1031                instructions: optional_node_inst_1.to_vec(),
1032                decoded_instructions: vec![
1033                    DecodedInstruction::UnconditionalAbort,
1034                    DecodedInstruction::UnconditionalAbort,
1035                ],
1036            }],
1037            debug_info: Some(DecodedDebugInfo { symbol_table: debug_symbol_table }),
1038        };
1039        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1040    }
1041
1042    #[test]
1043    fn test_valid_composite_bind() {
1044        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1045        bytecode.push(BYTECODE_DISABLE_DEBUG);
1046        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
1047
1048        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1049        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1050        bytecode.extend_from_slice(&device_name);
1051
1052        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1053        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1054        bytecode.extend_from_slice(&primary_node_name);
1055
1056        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1057        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1058        bytecode.extend_from_slice(&node_name_1);
1059
1060        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
1061        bytecode.extend_from_slice(&[4, 0, 0, 0]);
1062        bytecode.extend_from_slice(&node_name_2);
1063
1064        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1065        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1066        let additional_node_inst_2 = [0x30, 0x30];
1067
1068        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1069            + ((NODE_TYPE_HEADER_SZ * 3)
1070                + primary_node_inst.len()
1071                + additional_node_inst_1.len()
1072                + additional_node_inst_2.len()) as u32;
1073        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1074
1075        // Add device name ID.
1076        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1077
1078        // Add the node instructions.
1079        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1080        bytecode.extend_from_slice(&primary_node_inst);
1081        append_node_header(
1082            &mut bytecode,
1083            RawNodeType::Additional,
1084            3,
1085            additional_node_inst_1.len() as u32,
1086        );
1087        bytecode.extend_from_slice(&additional_node_inst_1);
1088        append_node_header(
1089            &mut bytecode,
1090            RawNodeType::Additional,
1091            4,
1092            additional_node_inst_2.len() as u32,
1093        );
1094        bytecode.extend_from_slice(&additional_node_inst_2);
1095
1096        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1097        expected_symbol_table.insert(1, "IBIS".to_string());
1098        expected_symbol_table.insert(2, "RAIL".to_string());
1099        expected_symbol_table.insert(3, "COOT".to_string());
1100        expected_symbol_table.insert(4, "PLOVER".to_string());
1101
1102        let rules = DecodedCompositeBindRules {
1103            symbol_table: expected_symbol_table,
1104            device_name_id: 1,
1105            primary_node: Node {
1106                name_id: 2,
1107                instructions: primary_node_inst.to_vec(),
1108                decoded_instructions: vec![
1109                    DecodedInstruction::UnconditionalAbort,
1110                    DecodedInstruction::Condition(DecodedCondition {
1111                        is_equal: true,
1112                        lhs: Symbol::NumberValue(0x5000000),
1113                        rhs: Symbol::NumberValue(0x200010),
1114                    }),
1115                ],
1116            },
1117            additional_nodes: vec![
1118                Node {
1119                    name_id: 3,
1120                    instructions: additional_node_inst_1.to_vec(),
1121                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1122                        is_equal: false,
1123                        lhs: Symbol::NumberValue(0x2000000),
1124                        rhs: Symbol::NumberValue(0x10000000),
1125                    })],
1126                },
1127                Node {
1128                    name_id: 4,
1129                    instructions: additional_node_inst_2.to_vec(),
1130                    decoded_instructions: vec![
1131                        DecodedInstruction::UnconditionalAbort,
1132                        DecodedInstruction::UnconditionalAbort,
1133                    ],
1134                },
1135            ],
1136            optional_nodes: vec![],
1137            debug_info: None,
1138        };
1139        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1140    }
1141
1142    #[test]
1143    fn test_valid_composite_bind_with_optional() {
1144        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1145        bytecode.push(BYTECODE_DISABLE_DEBUG);
1146        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
1147
1148        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1149        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1150        bytecode.extend_from_slice(&device_name);
1151
1152        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1153        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1154        bytecode.extend_from_slice(&primary_node_name);
1155
1156        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1157        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1158        bytecode.extend_from_slice(&node_name_1);
1159
1160        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
1161        bytecode.extend_from_slice(&[4, 0, 0, 0]);
1162        bytecode.extend_from_slice(&node_name_2);
1163
1164        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1165        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1166        let optional_node_inst_1 = [0x30, 0x30];
1167
1168        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1169            + ((NODE_TYPE_HEADER_SZ * 3)
1170                + primary_node_inst.len()
1171                + additional_node_inst_1.len()
1172                + optional_node_inst_1.len()) as u32;
1173        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1174
1175        // Add device name ID.
1176        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1177
1178        // Add the node instructions.
1179        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1180        bytecode.extend_from_slice(&primary_node_inst);
1181        append_node_header(
1182            &mut bytecode,
1183            RawNodeType::Additional,
1184            3,
1185            additional_node_inst_1.len() as u32,
1186        );
1187        bytecode.extend_from_slice(&additional_node_inst_1);
1188        append_node_header(
1189            &mut bytecode,
1190            RawNodeType::Optional,
1191            4,
1192            optional_node_inst_1.len() as u32,
1193        );
1194        bytecode.extend_from_slice(&optional_node_inst_1);
1195
1196        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1197        expected_symbol_table.insert(1, "IBIS".to_string());
1198        expected_symbol_table.insert(2, "RAIL".to_string());
1199        expected_symbol_table.insert(3, "COOT".to_string());
1200        expected_symbol_table.insert(4, "PLOVER".to_string());
1201
1202        let rules = DecodedCompositeBindRules {
1203            symbol_table: expected_symbol_table,
1204            device_name_id: 1,
1205            primary_node: Node {
1206                name_id: 2,
1207                instructions: primary_node_inst.to_vec(),
1208                decoded_instructions: vec![
1209                    DecodedInstruction::UnconditionalAbort,
1210                    DecodedInstruction::Condition(DecodedCondition {
1211                        is_equal: true,
1212                        lhs: Symbol::NumberValue(0x5000000),
1213                        rhs: Symbol::NumberValue(0x200010),
1214                    }),
1215                ],
1216            },
1217            additional_nodes: vec![Node {
1218                name_id: 3,
1219                instructions: additional_node_inst_1.to_vec(),
1220                decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1221                    is_equal: false,
1222                    lhs: Symbol::NumberValue(0x2000000),
1223                    rhs: Symbol::NumberValue(0x10000000),
1224                })],
1225            }],
1226            optional_nodes: vec![Node {
1227                name_id: 4,
1228                instructions: optional_node_inst_1.to_vec(),
1229                decoded_instructions: vec![
1230                    DecodedInstruction::UnconditionalAbort,
1231                    DecodedInstruction::UnconditionalAbort,
1232                ],
1233            }],
1234            debug_info: None,
1235        };
1236        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1237    }
1238
1239    #[test]
1240    fn test_primary_node_only() {
1241        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1242        bytecode.push(BYTECODE_DISABLE_DEBUG);
1243        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1244
1245        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1246        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1247        bytecode.extend_from_slice(&device_name);
1248
1249        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1250        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1251        bytecode.extend_from_slice(&primary_node_name);
1252
1253        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1254
1255        let composite_insts_sz =
1256            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1257        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1258
1259        // Add device name ID.
1260        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1261
1262        // Add the node instructions.
1263        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1264        bytecode.extend_from_slice(&primary_node_inst);
1265
1266        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1267        expected_symbol_table.insert(1, "IBIS".to_string());
1268        expected_symbol_table.insert(2, "COOT".to_string());
1269
1270        assert_eq!(
1271            DecodedRules::Composite(DecodedCompositeBindRules {
1272                symbol_table: expected_symbol_table,
1273                device_name_id: 1,
1274                primary_node: Node {
1275                    name_id: 2,
1276                    instructions: primary_node_inst.to_vec(),
1277                    decoded_instructions: vec![
1278                        DecodedInstruction::UnconditionalAbort,
1279                        DecodedInstruction::Condition(DecodedCondition {
1280                            is_equal: true,
1281                            lhs: Symbol::NumberValue(0x5000000),
1282                            rhs: Symbol::NumberValue(0x200010),
1283                        }),
1284                    ],
1285                },
1286                additional_nodes: vec![],
1287                optional_nodes: vec![],
1288                debug_info: None,
1289            }),
1290            DecodedRules::new(bytecode).unwrap()
1291        );
1292    }
1293
1294    #[test]
1295    fn test_missing_device_name() {
1296        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1297        bytecode.push(BYTECODE_DISABLE_DEBUG);
1298        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
1299
1300        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1301        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1302        bytecode.extend_from_slice(&primary_node_name);
1303
1304        let primary_node_inst = [0x30];
1305        let composite_insts_sz =
1306            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1307        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1308        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1309
1310        append_node_header(&mut bytecode, RawNodeType::Primary, 1, primary_node_inst.len() as u32);
1311        bytecode.extend_from_slice(&primary_node_inst);
1312
1313        assert_eq!(Err(BytecodeError::MissingDeviceNameInSymbolTable), DecodedRules::new(bytecode));
1314    }
1315
1316    #[test]
1317    fn test_missing_node_name() {
1318        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1319        bytecode.push(BYTECODE_DISABLE_DEBUG);
1320        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
1321
1322        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1323        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1324        bytecode.extend_from_slice(&primary_node_name);
1325
1326        let primary_node_inst = [0x30];
1327        let composite_insts_sz =
1328            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1329        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1330        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1331
1332        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1333        bytecode.extend_from_slice(&primary_node_inst);
1334
1335        assert_eq!(Err(BytecodeError::MissingNodeIdInSymbolTable), DecodedRules::new(bytecode));
1336    }
1337
1338    #[test]
1339    fn test_missing_primary_node() {
1340        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1341        bytecode.push(BYTECODE_DISABLE_DEBUG);
1342        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1343
1344        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1345        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1346        bytecode.extend_from_slice(&device_name);
1347
1348        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1349        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1350        bytecode.extend_from_slice(&primary_node_name);
1351
1352        let additional_node_name: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1353        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1354        bytecode.extend_from_slice(&additional_node_name);
1355
1356        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1357        let additional_node_inst_2 = [0x30];
1358
1359        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1360            + ((NODE_TYPE_HEADER_SZ * 2)
1361                + additional_node_inst_1.len()
1362                + additional_node_inst_2.len()) as u32;
1363        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1364
1365        // Add device name ID.
1366        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1367
1368        // Add the node instructions.
1369        append_node_header(
1370            &mut bytecode,
1371            RawNodeType::Additional,
1372            2,
1373            additional_node_inst_1.len() as u32,
1374        );
1375        bytecode.extend_from_slice(&additional_node_inst_1);
1376        append_node_header(
1377            &mut bytecode,
1378            RawNodeType::Additional,
1379            3,
1380            additional_node_inst_2.len() as u32,
1381        );
1382        bytecode.extend_from_slice(&additional_node_inst_2);
1383
1384        assert_eq!(Err(BytecodeError::InvalidPrimaryNode), DecodedRules::new(bytecode));
1385    }
1386
1387    #[test]
1388    fn test_primary_node_incorrect_order() {
1389        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1390        bytecode.push(BYTECODE_DISABLE_DEBUG);
1391        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1392
1393        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1394        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1395        bytecode.extend_from_slice(&device_name);
1396
1397        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1398        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1399        bytecode.extend_from_slice(&primary_node_name);
1400
1401        let additional_node_name: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1402        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1403        bytecode.extend_from_slice(&additional_node_name);
1404
1405        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1406        let additional_node_inst = [0x30];
1407
1408        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1409            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1410                as u32;
1411        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1412
1413        // Add device name ID.
1414        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1415
1416        // Add the node instructions.
1417        append_node_header(
1418            &mut bytecode,
1419            RawNodeType::Additional,
1420            3,
1421            additional_node_inst.len() as u32,
1422        );
1423        bytecode.extend_from_slice(&additional_node_inst);
1424        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1425        bytecode.extend_from_slice(&primary_node_inst);
1426
1427        assert_eq!(Err(BytecodeError::InvalidPrimaryNode), DecodedRules::new(bytecode));
1428    }
1429
1430    #[test]
1431    fn test_multiple_primary_nodes() {
1432        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1433        bytecode.push(BYTECODE_DISABLE_DEBUG);
1434        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1435
1436        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1437        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1438        bytecode.extend_from_slice(&device_name);
1439
1440        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1441        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1442        bytecode.extend_from_slice(&primary_node_name);
1443
1444        let primary_node_name_2: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1445        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1446        bytecode.extend_from_slice(&primary_node_name_2);
1447
1448        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1449        let primary_node_inst_2 = [0x30];
1450
1451        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1452            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + primary_node_inst_2.len())
1453                as u32;
1454        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1455
1456        // Add device name ID.
1457        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1458
1459        // Add the node instructions.
1460        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1461        bytecode.extend_from_slice(&primary_node_inst);
1462        append_node_header(
1463            &mut bytecode,
1464            RawNodeType::Primary,
1465            3,
1466            primary_node_inst_2.len() as u32,
1467        );
1468        bytecode.extend_from_slice(&primary_node_inst_2);
1469
1470        assert_eq!(Err(BytecodeError::MultiplePrimaryNodes), DecodedRules::new(bytecode));
1471    }
1472
1473    #[test]
1474    fn test_invalid_node_type() {
1475        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1476        bytecode.push(BYTECODE_DISABLE_DEBUG);
1477        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1478
1479        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1480        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1481        bytecode.extend_from_slice(&device_name);
1482
1483        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1484        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1485        bytecode.extend_from_slice(&primary_node_name);
1486
1487        let primary_node_inst = [0x30];
1488
1489        let composite_insts_sz =
1490            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1491        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1492
1493        // Add device name ID.
1494        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1495
1496        // Add the node instructions with an invalid node type.
1497        bytecode.push(0x53);
1498        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1499        bytecode.extend_from_slice(&(primary_node_inst.len() as u32).to_le_bytes());
1500        bytecode.extend_from_slice(&primary_node_inst);
1501
1502        assert_eq!(Err(BytecodeError::InvalidNodeType(0x53)), DecodedRules::new(bytecode));
1503    }
1504
1505    #[test]
1506    fn test_incorrect_node_section_sz_overlap() {
1507        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1508        bytecode.push(BYTECODE_DISABLE_DEBUG);
1509        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
1510
1511        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1512        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1513        bytecode.extend_from_slice(&device_name);
1514
1515        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1516        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1517        bytecode.extend_from_slice(&primary_node_name);
1518
1519        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1520        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1521        bytecode.extend_from_slice(&node_name_1);
1522
1523        let primary_node_inst = [0x30];
1524        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1525
1526        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1527            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1528                as u32;
1529        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1530
1531        // Add device name ID.
1532        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1533
1534        // Add the primary node instructions with a size that overlaps to the next
1535        // node.
1536        append_node_header(&mut bytecode, RawNodeType::Primary, 2, 7);
1537        bytecode.extend_from_slice(&primary_node_inst);
1538
1539        append_node_header(
1540            &mut bytecode,
1541            RawNodeType::Additional,
1542            3,
1543            additional_node_inst.len() as u32,
1544        );
1545        bytecode.extend_from_slice(&additional_node_inst);
1546
1547        // Instructions for the primary node end, the next byte is the node type for the next node.
1548        assert_eq!(
1549            Err(BytecodeError::InvalidOp(RawNodeType::Additional as u8)),
1550            DecodedRules::new(bytecode)
1551        );
1552    }
1553
1554    #[test]
1555    fn test_incorrect_node_section_sz_undersize() {
1556        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1557        bytecode.push(BYTECODE_DISABLE_DEBUG);
1558        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
1559
1560        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1561        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1562        bytecode.extend_from_slice(&device_name);
1563
1564        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1565        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1566        bytecode.extend_from_slice(&primary_node_name);
1567
1568        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1569        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1570        bytecode.extend_from_slice(&node_name_1);
1571
1572        let primary_node_inst = [0x30];
1573        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1574
1575        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1576            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1577                as u32;
1578        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1579
1580        // Add device name ID.
1581        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1582
1583        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1584        bytecode.extend_from_slice(&primary_node_inst);
1585
1586        // Add the additional node with a size that's too small.
1587        append_node_header(&mut bytecode, RawNodeType::Additional, 3, 1);
1588        bytecode.extend_from_slice(&additional_node_inst);
1589
1590        // Reach end when trying to read in value type after the inequality operator (0x02).
1591        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
1592    }
1593
1594    #[test]
1595    fn test_incorrect_node_section_sz_oversize() {
1596        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1597        bytecode.push(BYTECODE_DISABLE_DEBUG);
1598        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1599
1600        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1601        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1602        bytecode.extend_from_slice(&device_name);
1603
1604        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1605        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1606        bytecode.extend_from_slice(&primary_node_name);
1607
1608        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1609
1610        let composite_insts_sz =
1611            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1612        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1613
1614        // Add device name ID.
1615        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1616
1617        // Add primary node instructions with a size that exceed the entire instruction size.
1618        append_node_header(&mut bytecode, RawNodeType::Primary, 2, 50);
1619        bytecode.extend_from_slice(&primary_node_inst);
1620
1621        assert_eq!(Err(BytecodeError::IncorrectNodeSectionSize), DecodedRules::new(bytecode));
1622    }
1623
1624    #[test]
1625    fn test_composite_header_in_noncomposite_bytecode() {
1626        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1627        bytecode.push(BYTECODE_DISABLE_DEBUG);
1628        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1629
1630        let str_1: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1631        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1632        bytecode.extend_from_slice(&str_1);
1633
1634        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1635        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1636        bytecode.extend_from_slice(&primary_node_name);
1637
1638        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1639
1640        let composite_insts_sz =
1641            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1642        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1643
1644        // Add device name ID.
1645        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1646
1647        // Add the node instructions.
1648        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
1649        bytecode.extend_from_slice(&primary_node_inst);
1650
1651        assert_eq!(
1652            Err(BytecodeError::InvalidHeader(INSTRUCTION_MAGIC_NUM, COMPOSITE_MAGIC_NUM)),
1653            DecodedBindRules::from_bytecode(bytecode)
1654        );
1655    }
1656
1657    #[test]
1658    fn test_inst_header_in_composite_bytecode() {
1659        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1660        bytecode.push(BYTECODE_DISABLE_DEBUG);
1661        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
1662
1663        let instructions = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x10, 0, 0, 0x10];
1664        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
1665        bytecode.extend_from_slice(&instructions);
1666
1667        assert_eq!(
1668            Err(BytecodeError::InvalidHeader(COMPOSITE_MAGIC_NUM, INSTRUCTION_MAGIC_NUM)),
1669            DecodedCompositeBindRules::from_bytecode(bytecode)
1670        );
1671    }
1672
1673    #[test]
1674    fn test_composite_with_compiler() {
1675        use crate::compiler::{
1676            CompiledBindRules, CompositeBindRules, CompositeNode, Symbol, SymbolicInstruction,
1677            SymbolicInstructionInfo,
1678        };
1679        use crate::parser::bind_library::ValueType;
1680
1681        let primary_node_inst = vec![SymbolicInstructionInfo {
1682            location: None,
1683            instruction: SymbolicInstruction::UnconditionalAbort,
1684        }];
1685
1686        let additional_node_inst = vec![
1687            SymbolicInstructionInfo {
1688                location: None,
1689                instruction: SymbolicInstruction::AbortIfEqual {
1690                    lhs: Symbol::Key("bobolink".to_string(), ValueType::Bool),
1691                    rhs: Symbol::BoolValue(false),
1692                },
1693            },
1694            SymbolicInstructionInfo {
1695                location: None,
1696                instruction: SymbolicInstruction::AbortIfNotEqual {
1697                    lhs: Symbol::Key("grackle".to_string(), ValueType::Number),
1698                    rhs: Symbol::NumberValue(1),
1699                },
1700            },
1701        ];
1702
1703        let bytecode = CompiledBindRules::CompositeBind(CompositeBindRules {
1704            device_name: "blackbird".to_string(),
1705            symbol_table: HashMap::new(),
1706            primary_node: CompositeNode {
1707                name: "meadowlark".to_string(),
1708                instructions: primary_node_inst,
1709            },
1710            additional_nodes: vec![CompositeNode {
1711                name: "cowbird".to_string(),
1712                instructions: additional_node_inst,
1713            }],
1714            optional_nodes: vec![],
1715            enable_debug: false,
1716        })
1717        .encode_to_bytecode()
1718        .unwrap();
1719
1720        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1721        expected_symbol_table.insert(1, "blackbird".to_string());
1722        expected_symbol_table.insert(2, "meadowlark".to_string());
1723        expected_symbol_table.insert(3, "cowbird".to_string());
1724        expected_symbol_table.insert(4, "bobolink".to_string());
1725        expected_symbol_table.insert(5, "grackle".to_string());
1726
1727        let primary_node_inst = [0x30];
1728        let additional_node_inst = [
1729            0x02, 0x0, 0x04, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // bobolink != false
1730            0x01, 0x0, 0x05, 0x0, 0x0, 0x0, 0x01, 0x1, 0x0, 0x0, 0x0, // grackle == 1
1731        ];
1732
1733        assert_eq!(
1734            DecodedRules::Composite(DecodedCompositeBindRules {
1735                symbol_table: expected_symbol_table,
1736                device_name_id: 1,
1737                primary_node: Node {
1738                    name_id: 2,
1739                    instructions: primary_node_inst.to_vec(),
1740                    decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
1741                },
1742                additional_nodes: vec![Node {
1743                    name_id: 3,
1744                    instructions: additional_node_inst.to_vec(),
1745                    decoded_instructions: vec![
1746                        DecodedInstruction::Condition(DecodedCondition {
1747                            is_equal: false,
1748                            lhs: Symbol::Key("bobolink".to_string(), ValueType::Str),
1749                            rhs: Symbol::BoolValue(false)
1750                        }),
1751                        DecodedInstruction::Condition(DecodedCondition {
1752                            is_equal: true,
1753                            lhs: Symbol::Key("grackle".to_string(), ValueType::Str),
1754                            rhs: Symbol::NumberValue(1)
1755                        })
1756                    ]
1757                }],
1758                optional_nodes: vec![],
1759                debug_info: None,
1760            }),
1761            DecodedRules::new(bytecode).unwrap()
1762        );
1763    }
1764
1765    #[test]
1766    fn test_composite_optional_with_compiler() {
1767        use crate::compiler::{
1768            CompiledBindRules, CompositeBindRules, CompositeNode, Symbol, SymbolicInstruction,
1769            SymbolicInstructionInfo,
1770        };
1771        use crate::parser::bind_library::ValueType;
1772
1773        let primary_node_inst = vec![SymbolicInstructionInfo {
1774            location: None,
1775            instruction: SymbolicInstruction::UnconditionalAbort,
1776        }];
1777
1778        let additional_node_inst = vec![
1779            SymbolicInstructionInfo {
1780                location: None,
1781                instruction: SymbolicInstruction::AbortIfEqual {
1782                    lhs: Symbol::Key("bobolink".to_string(), ValueType::Bool),
1783                    rhs: Symbol::BoolValue(false),
1784                },
1785            },
1786            SymbolicInstructionInfo {
1787                location: None,
1788                instruction: SymbolicInstruction::AbortIfNotEqual {
1789                    lhs: Symbol::Key("grackle".to_string(), ValueType::Number),
1790                    rhs: Symbol::NumberValue(1),
1791                },
1792            },
1793        ];
1794
1795        let optional_node_inst = vec![SymbolicInstructionInfo {
1796            location: None,
1797            instruction: SymbolicInstruction::AbortIfEqual {
1798                lhs: Symbol::Key("mockingbird".to_string(), ValueType::Bool),
1799                rhs: Symbol::BoolValue(false),
1800            },
1801        }];
1802
1803        let bytecode = CompiledBindRules::CompositeBind(CompositeBindRules {
1804            device_name: "blackbird".to_string(),
1805            symbol_table: HashMap::new(),
1806            primary_node: CompositeNode {
1807                name: "meadowlark".to_string(),
1808                instructions: primary_node_inst,
1809            },
1810            additional_nodes: vec![CompositeNode {
1811                name: "cowbird".to_string(),
1812                instructions: additional_node_inst,
1813            }],
1814            optional_nodes: vec![CompositeNode {
1815                name: "cowbird_optional".to_string(),
1816                instructions: optional_node_inst,
1817            }],
1818            enable_debug: false,
1819        })
1820        .encode_to_bytecode()
1821        .unwrap();
1822
1823        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1824        expected_symbol_table.insert(1, "blackbird".to_string());
1825        expected_symbol_table.insert(2, "meadowlark".to_string());
1826        expected_symbol_table.insert(3, "cowbird".to_string());
1827        expected_symbol_table.insert(4, "bobolink".to_string());
1828        expected_symbol_table.insert(5, "grackle".to_string());
1829        expected_symbol_table.insert(6, "cowbird_optional".to_string());
1830        expected_symbol_table.insert(7, "mockingbird".to_string());
1831
1832        let primary_node_inst = [0x30];
1833        let additional_node_inst = [
1834            0x02, 0x0, 0x04, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // bobolink != false
1835            0x01, 0x0, 0x05, 0x0, 0x0, 0x0, 0x01, 0x1, 0x0, 0x0, 0x0, // grackle == 1
1836        ];
1837
1838        let optional_node_inst = [
1839            0x02, 0x0, 0x07, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // mockingbird != false
1840        ];
1841
1842        assert_eq!(
1843            DecodedRules::Composite(DecodedCompositeBindRules {
1844                symbol_table: expected_symbol_table,
1845                device_name_id: 1,
1846                primary_node: Node {
1847                    name_id: 2,
1848                    instructions: primary_node_inst.to_vec(),
1849                    decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
1850                },
1851                additional_nodes: vec![Node {
1852                    name_id: 3,
1853                    instructions: additional_node_inst.to_vec(),
1854                    decoded_instructions: vec![
1855                        DecodedInstruction::Condition(DecodedCondition {
1856                            is_equal: false,
1857                            lhs: Symbol::Key("bobolink".to_string(), ValueType::Str),
1858                            rhs: Symbol::BoolValue(false)
1859                        }),
1860                        DecodedInstruction::Condition(DecodedCondition {
1861                            is_equal: true,
1862                            lhs: Symbol::Key("grackle".to_string(), ValueType::Str),
1863                            rhs: Symbol::NumberValue(1)
1864                        })
1865                    ]
1866                }],
1867                optional_nodes: vec![Node {
1868                    name_id: 6,
1869                    instructions: optional_node_inst.to_vec(),
1870                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1871                        is_equal: false,
1872                        lhs: Symbol::Key("mockingbird".to_string(), ValueType::Str),
1873                        rhs: Symbol::BoolValue(false)
1874                    })],
1875                }],
1876                debug_info: None,
1877            }),
1878            DecodedRules::new(bytecode).unwrap()
1879        );
1880    }
1881}