# bad blocks with block cycles should be tested in test_relocations
if = '(int32_t)BLOCK_CYCLES == -1'

[cases.test_badblocks_single]
defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
    'LFS_EMUBD_BADBLOCK_PROGERROR',
    'LFS_EMUBD_BADBLOCK_ERASEERROR',
    'LFS_EMUBD_BADBLOCK_READERROR',
    'LFS_EMUBD_BADBLOCK_PROGNOOP',
    'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
    for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) {
        lfs_emubd_setwear(cfg, badblock-1, 0) => 0;
        lfs_emubd_setwear(cfg, badblock, 0xffffffff) => 0;

        lfs_t lfs;
        lfs_format(&lfs, cfg) => 0;

        lfs_mount(&lfs, cfg) => 0;
        for (int i = 1; i < 10; i++) {
            uint8_t buffer[1024];
            for (int j = 0; j < NAMEMULT; j++) {
                buffer[j] = '0'+i;
            }
            buffer[NAMEMULT] = '\0';
            lfs_mkdir(&lfs, (char*)buffer) => 0;

            buffer[NAMEMULT] = '/';
            for (int j = 0; j < NAMEMULT; j++) {
                buffer[j+NAMEMULT+1] = '0'+i;
            }
            buffer[2*NAMEMULT+1] = '\0';
            lfs_file_t file;
            lfs_file_open(&lfs, &file, (char*)buffer,
                    LFS_O_WRONLY | LFS_O_CREAT) => 0;
            
            lfs_size_t size = NAMEMULT;
            for (int j = 0; j < i*FILEMULT; j++) {
                lfs_file_write(&lfs, &file, buffer, size) => size;
            }

            lfs_file_close(&lfs, &file) => 0;
        }
        lfs_unmount(&lfs) => 0;

        lfs_mount(&lfs, cfg) => 0;
        for (int i = 1; i < 10; i++) {
            uint8_t buffer[1024];
            for (int j = 0; j < NAMEMULT; j++) {
                buffer[j] = '0'+i;
            }
            buffer[NAMEMULT] = '\0';
            struct lfs_info info;
            lfs_stat(&lfs, (char*)buffer, &info) => 0;
            info.type => LFS_TYPE_DIR;

            buffer[NAMEMULT] = '/';
            for (int j = 0; j < NAMEMULT; j++) {
                buffer[j+NAMEMULT+1] = '0'+i;
            }
            buffer[2*NAMEMULT+1] = '\0';
            lfs_file_t file;
            lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
            
            int size = NAMEMULT;
            for (int j = 0; j < i*FILEMULT; j++) {
                uint8_t rbuffer[1024];
                lfs_file_read(&lfs, &file, rbuffer, size) => size;
                memcmp(buffer, rbuffer, size) => 0;
            }

            lfs_file_close(&lfs, &file) => 0;
        }
        lfs_unmount(&lfs) => 0;
    }
'''

[cases.test_badblocks_region_corruption] # (causes cascading failures)
defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
    'LFS_EMUBD_BADBLOCK_PROGERROR',
    'LFS_EMUBD_BADBLOCK_ERASEERROR',
    'LFS_EMUBD_BADBLOCK_READERROR',
    'LFS_EMUBD_BADBLOCK_PROGNOOP',
    'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
    for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
        lfs_emubd_setwear(cfg, i+2, 0xffffffff) => 0;
    }

    lfs_t lfs;
    lfs_format(&lfs, cfg) => 0;

    lfs_mount(&lfs, cfg) => 0;
    for (int i = 1; i < 10; i++) {
        uint8_t buffer[1024];
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j] = '0'+i;
        }
        buffer[NAMEMULT] = '\0';
        lfs_mkdir(&lfs, (char*)buffer) => 0;

        buffer[NAMEMULT] = '/';
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j+NAMEMULT+1] = '0'+i;
        }
        buffer[2*NAMEMULT+1] = '\0';
        lfs_file_t file;
        lfs_file_open(&lfs, &file, (char*)buffer,
                LFS_O_WRONLY | LFS_O_CREAT) => 0;
        
        lfs_size_t size = NAMEMULT;
        for (int j = 0; j < i*FILEMULT; j++) {
            lfs_file_write(&lfs, &file, buffer, size) => size;
        }

        lfs_file_close(&lfs, &file) => 0;
    }
    lfs_unmount(&lfs) => 0;

    lfs_mount(&lfs, cfg) => 0;
    for (int i = 1; i < 10; i++) {
        uint8_t buffer[1024];
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j] = '0'+i;
        }
        buffer[NAMEMULT] = '\0';
        struct lfs_info info;
        lfs_stat(&lfs, (char*)buffer, &info) => 0;
        info.type => LFS_TYPE_DIR;

        buffer[NAMEMULT] = '/';
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j+NAMEMULT+1] = '0'+i;
        }
        buffer[2*NAMEMULT+1] = '\0';
        lfs_file_t file;
        lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
        
        lfs_size_t size = NAMEMULT;
        for (int j = 0; j < i*FILEMULT; j++) {
            uint8_t rbuffer[1024];
            lfs_file_read(&lfs, &file, rbuffer, size) => size;
            memcmp(buffer, rbuffer, size) => 0;
        }

        lfs_file_close(&lfs, &file) => 0;
    }
    lfs_unmount(&lfs) => 0;
'''

[cases.test_badblocks_alternating_corruption] # (causes cascading failures)
defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
    'LFS_EMUBD_BADBLOCK_PROGERROR',
    'LFS_EMUBD_BADBLOCK_ERASEERROR',
    'LFS_EMUBD_BADBLOCK_READERROR',
    'LFS_EMUBD_BADBLOCK_PROGNOOP',
    'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
    for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
        lfs_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0;
    }

    lfs_t lfs;
    lfs_format(&lfs, cfg) => 0;

    lfs_mount(&lfs, cfg) => 0;
    for (int i = 1; i < 10; i++) {
        uint8_t buffer[1024];
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j] = '0'+i;
        }
        buffer[NAMEMULT] = '\0';
        lfs_mkdir(&lfs, (char*)buffer) => 0;

        buffer[NAMEMULT] = '/';
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j+NAMEMULT+1] = '0'+i;
        }
        buffer[2*NAMEMULT+1] = '\0';
        lfs_file_t file;
        lfs_file_open(&lfs, &file, (char*)buffer,
                LFS_O_WRONLY | LFS_O_CREAT) => 0;
        
        lfs_size_t size = NAMEMULT;
        for (int j = 0; j < i*FILEMULT; j++) {
            lfs_file_write(&lfs, &file, buffer, size) => size;
        }

        lfs_file_close(&lfs, &file) => 0;
    }
    lfs_unmount(&lfs) => 0;

    lfs_mount(&lfs, cfg) => 0;
    for (int i = 1; i < 10; i++) {
        uint8_t buffer[1024];
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j] = '0'+i;
        }
        buffer[NAMEMULT] = '\0';
        struct lfs_info info;
        lfs_stat(&lfs, (char*)buffer, &info) => 0;
        info.type => LFS_TYPE_DIR;

        buffer[NAMEMULT] = '/';
        for (int j = 0; j < NAMEMULT; j++) {
            buffer[j+NAMEMULT+1] = '0'+i;
        }
        buffer[2*NAMEMULT+1] = '\0';
        lfs_file_t file;
        lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
        
        lfs_size_t size = NAMEMULT;
        for (int j = 0; j < i*FILEMULT; j++) {
            uint8_t rbuffer[1024];
            lfs_file_read(&lfs, &file, rbuffer, size) => size;
            memcmp(buffer, rbuffer, size) => 0;
        }

        lfs_file_close(&lfs, &file) => 0;
    }
    lfs_unmount(&lfs) => 0;
'''

# other corner cases
[cases.test_badblocks_superblocks] # (corrupt 1 or 0)
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
    'LFS_EMUBD_BADBLOCK_PROGERROR',
    'LFS_EMUBD_BADBLOCK_ERASEERROR',
    'LFS_EMUBD_BADBLOCK_READERROR',
    'LFS_EMUBD_BADBLOCK_PROGNOOP',
    'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
code = '''
    lfs_emubd_setwear(cfg, 0, 0xffffffff) => 0;
    lfs_emubd_setwear(cfg, 1, 0xffffffff) => 0;

    lfs_t lfs;
    lfs_format(&lfs, cfg) => LFS_ERR_NOSPC;
    lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
