<commit_before>extern crate nom;
extern crate classfile_parser;

// use std::fs::File;
// use std::io::Read;

use nom::IResult;

use classfile_parser::class_parser;
use classfile_parser::constant_info::ConstantInfo;


#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../java-assets/compiled-classes/BasicClass.class");
    let res = class_parser(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({}), fields({}), methods({}), attributes({}), access({:?})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count, c.fields_count, c.methods_count, c.attributes_count, c.access_flags);

            let mut code_const_index = 0;

            println!("Constant pool:");
            for (const_index, const_item) in c.const_pool.iter().enumerate() {
                println!("\t[{}] = {:?}", (const_index + 1), const_item);
                match *const_item {
                    ConstantInfo::Utf8(ref c) => {
                        if c.utf8_string == "Code" {
                            code_const_index = (const_index + 1) as u16;
                        }
                    },
                    _ => {},
                }
            }
            println!("Code index = {}", code_const_index);

            println!("Interfaces:");
            let mut interface_index = 0;
            for i in &c.interfaces {
                println!("\t[{}] = const[{}] = {:?}", interface_index, i, c.const_pool[(i-1) as usize]);

                interface_index += 1;
            }
            println!("Fields:");
            let mut field_index = 0;
            for f in &c.fields {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", field_index, f.name_index, c.const_pool[(f.name_index - 1) as usize], f.access_flags);
                field_index += 1;
            }
            println!("Methods:");
            let mut method_index = 0;
            for m in &c.methods {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", method_index, m.name_index, c.const_pool[(m.name_index - 1) as usize], m.access_flags);
                method_index += 1;

                for a in &m.attributes {
                    if a.attribute_name_index == code_const_index {
                        println!("\t\tCode attr found, len = {}", a.attribute_length);
                        let code_result = classfile_parser::attribute_info::code_attribute_parser(&a.info);
                        match code_result {
                            IResult::Done(_, code) => {
                                println!("\t\t\tCode! code_length = {}", code.code_length);
                            },
                            _ => panic!("Not a valid code attr?"),

                        }
                    }
                    else {
                        println!("\t\tAttribute: {:?}", a);
                    }
                }
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../java-assets/compiled-classes/malformed.class");
    let res = class_parser(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

// #[test]
// fn test_constant_utf8() {
//     let hello_world_data = &[
//         // 0x01, // tag = 1
//         0x00, 0x0C, // length = 12
//         0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
//     ];
//     let res = const_utf8(hello_world_data);

//     match res {
//         IResult::Done(_, c) =>
//         match c {
//             Constant::Utf8(ref s) =>
//                  println!("Valid UTF8 const: {}", s.utf8_string),
//             _ => panic!("It's a const, but of what type?")
//         },
//         _ => panic!("Not a UTF type const?"),
//     };
// }<commit_msg>Add basic parsing test for StackMapTable<commit_after>extern crate nom;
extern crate classfile_parser;

// use std::fs::File;
// use std::io::Read;

use nom::IResult;

use classfile_parser::class_parser;
use classfile_parser::constant_info::ConstantInfo;


#[test]
fn test_valid_class() {
    let valid_class = include_bytes!("../java-assets/compiled-classes/BasicClass.class");
    let res = class_parser(valid_class);
    match res {
        IResult::Done(_, c) => {
            println!("Valid class file, version {},{} const_pool({}), this=const[{}], super=const[{}], interfaces({}), fields({}), methods({}), attributes({}), access({:?})", c.major_version, c.minor_version, c.const_pool_size, c.this_class, c.super_class, c.interfaces_count, c.fields_count, c.methods_count, c.attributes_count, c.access_flags);

            let mut code_const_index = 0;

            println!("Constant pool:");
            for (const_index, const_item) in c.const_pool.iter().enumerate() {
                println!("\t[{}] = {:?}", (const_index + 1), const_item);
                match *const_item {
                    ConstantInfo::Utf8(ref c) => {
                        if c.utf8_string == "Code" {
                            code_const_index = (const_index + 1) as u16;
                        }
                    },
                    _ => {},
                }
            }
            println!("Code index = {}", code_const_index);

            println!("Interfaces:");
            let mut interface_index = 0;
            for i in &c.interfaces {
                println!("\t[{}] = const[{}] = {:?}", interface_index, i, c.const_pool[(i-1) as usize]);

                interface_index += 1;
            }
            println!("Fields:");
            let mut field_index = 0;
            for f in &c.fields {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", field_index, f.name_index, c.const_pool[(f.name_index - 1) as usize], f.access_flags);
                field_index += 1;
            }
            println!("Methods:");
            let mut method_index = 0;
            for m in &c.methods {
                println!("\t[{}] Name(const[{}] = {:?}) - access({:?})", method_index, m.name_index, c.const_pool[(m.name_index - 1) as usize], m.access_flags);
                method_index += 1;

                for a in &m.attributes {
                    if a.attribute_name_index == code_const_index {
                        println!("\t\tCode attr found, len = {}", a.attribute_length);
                        let code_result = classfile_parser::attribute_info::code_attribute_parser(&a.info);
                        match code_result {
                            IResult::Done(_, code) => {
                                println!("\t\t\tCode! code_length = {}", code.code_length);
                            },
                            _ => panic!("Not a valid code attr?"),

                        }
                    }
                    else {
                        println!("\t\tAttribute: {:?}", a);
                    }
                }
            }
        },
        _ => panic!("Not a class file"),
    };
}

#[test]
fn test_malformed_class() {
    let malformed_class = include_bytes!("../java-assets/compiled-classes/malformed.class");
    let res = class_parser(malformed_class);
    match res {
        IResult::Done(_, _) => panic!("The file is not valid and shouldn't be parsed"),
        _ => res,
    };
}

#[test]
fn test_stack_map_table() {
    let stack_map_class = include_bytes!("../java-assets/compiled-classes/Factorial.class");
    let res = class_parser(stack_map_class);
    match res {
        IResult::Done(_, c) => {
            use classfile_parser::attribute_info::code_attribute_parser;
            use classfile_parser::attribute_info::stack_map_table_attribute_parser;

            assert_eq!(c.methods.len(), 2);
            assert_eq!(c.methods.len(), c.methods_count as usize);

            let method = &c.methods[1];
            assert_eq!(method.attributes.len(), 1);
            assert_eq!(method.attributes.len(), method.attributes_count as usize);

            let code = code_attribute_parser(&method.attributes[0].info).to_result().unwrap();
            assert_eq!(code.attributes_count, 1);

            let p = stack_map_table_attribute_parser(&code.attributes[0].info);
            match p {
                IResult::Done(_, a) => {
                    assert_eq!(a.entries.len(), a.number_of_entries as usize);
                    assert_eq!(a.entries.len(), 2);

                    use classfile_parser::attribute_info::StackMapFrame::*;
                    match a.entries[0] {
                        SameFrame { .. } => {},
                        _ => panic!("unexpected frame type for frame 0"),
                    };
                    match a.entries[1] {
                        SameLocals1StackItemFrame { .. } => {},
                        _ => panic!("unexpected frame type for frame 1: {:?}", &a.entries[1]),
                    };
                },
                _ => panic!("failed to parse StackMapTable"),
            };

        },
        _ => panic!("not a class file"),
    };
}

// #[test]
// fn test_constant_utf8() {
//     let hello_world_data = &[
//         // 0x01, // tag = 1
//         0x00, 0x0C, // length = 12
//         0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21 // 'Hello world!' in UTF8
//     ];
//     let res = const_utf8(hello_world_data);

//     match res {
//         IResult::Done(_, c) =>
//         match c {
//             Constant::Utf8(ref s) =>
//                  println!("Valid UTF8 const: {}", s.utf8_string),
//             _ => panic!("It's a const, but of what type?")
//         },
//         _ => panic!("Not a UTF type const?"),
//     };
// }
{'fraction_non_alphanumeric': 0.1555914086921448, 'fraction_numerical': 0.014218009478672985, 'mean_word_length': 1.6689989235737352, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1311979', 'n_tokens_mistral': 3089, 'n_tokens_neox': 2901, 'n_words': 588}