mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Generated v2 prefixes
This commit is contained in:
		
							
								
								
									
										445
									
								
								tests/test_alloc.sh → tests/test_alloc.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										445
									
								
								tests/test_alloc.sh → tests/test_alloc.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @@ -1,127 +1,201 @@ | ||||
| #!/bin/bash | ||||
| set -euE | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
| # allocator tests | ||||
| # note for these to work there are a number constraints on the device geometry | ||||
| if = 'LFS2_BLOCK_CYCLES == -1' | ||||
| 
 | ||||
| [[case]] # parallel allocation test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs2_file_t files[FILES]; | ||||
| 
 | ||||
| echo "=== Allocator tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
| 
 | ||||
| SIZE=15000 | ||||
| 
 | ||||
| lfs2_mkdir() { | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "$1") => 0; | ||||
|     lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
| 
 | ||||
| lfs2_remove() { | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "$1/eggs") => 0; | ||||
|     lfs2_remove(&lfs2, "$1/bacon") => 0; | ||||
|     lfs2_remove(&lfs2, "$1/pancakes") => 0; | ||||
|     lfs2_remove(&lfs2, "$1") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
| 
 | ||||
| lfs2_alloc_singleproc() { | ||||
| scripts/test.py << TEST | ||||
|     const char *names[] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs2_file_t files[sizeof(names)/sizeof(names[0])]; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||
|         sprintf(path, "$1/%s", names[n]); | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs2_file_open(&lfs2, &files[n], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     } | ||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||
|         lfs2_size_t size = strlen(names[n]); | ||||
|         for (int i = 0; i < $SIZE; i++) { | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         size = strlen(names[n]); | ||||
|         for (lfs2_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_write(&lfs2, &files[n], names[n], size) => size; | ||||
|         } | ||||
|     } | ||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         lfs2_file_close(&lfs2, &files[n]) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
| 
 | ||||
| lfs2_alloc_multiproc() { | ||||
| for name in bacon eggs pancakes | ||||
| do | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "$1/$name", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     lfs2_size_t size = strlen("$name"); | ||||
|     memcpy(buffer, "$name", size); | ||||
|     for (int i = 0; i < $SIZE; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         for (lfs2_size_t i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, names[n], size) == 0); | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| done | ||||
| } | ||||
| ''' | ||||
| 
 | ||||
| lfs2_verify() { | ||||
| for name in bacon eggs pancakes | ||||
| do | ||||
| scripts/test.py << TEST | ||||
| [[case]] # serial allocation test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
| 
 | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "$1/$name", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_size_t size = strlen("$name"); | ||||
|     for (int i = 0; i < $SIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "$name", size) => 0; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| done | ||||
| } | ||||
| 
 | ||||
| echo "--- Single-process allocation test ---" | ||||
| lfs2_mkdir singleproc | ||||
| lfs2_alloc_singleproc singleproc | ||||
| lfs2_verify singleproc | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         memcpy(buffer, names[n], size); | ||||
|         for (int i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| 
 | ||||
| echo "--- Multi-process allocation test ---" | ||||
| lfs2_mkdir multiproc | ||||
| lfs2_alloc_multiproc multiproc | ||||
| lfs2_verify multiproc | ||||
| lfs2_verify singleproc | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int n = 0; n < FILES; n++) { | ||||
|         sprintf(path, "breakfast/%s", names[n]); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         size = strlen(names[n]); | ||||
|         for (int i = 0; i < SIZE; i += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, names[n], size) == 0); | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Single-process reuse test ---" | ||||
| lfs2_remove singleproc | ||||
| lfs2_mkdir singleprocreuse | ||||
| lfs2_alloc_singleproc singleprocreuse | ||||
| lfs2_verify singleprocreuse | ||||
| lfs2_verify multiproc | ||||
| [[case]] # parallel allocation reuse test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| define.CYCLES = [1, 10] | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs2_file_t files[FILES]; | ||||
| 
 | ||||
| echo "--- Multi-process reuse test ---" | ||||
| lfs2_remove multiproc | ||||
| lfs2_mkdir multiprocreuse | ||||
| lfs2_alloc_singleproc multiprocreuse | ||||
| lfs2_verify multiprocreuse | ||||
| lfs2_verify singleprocreuse | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
| echo "--- Cleanup ---" | ||||
| lfs2_remove multiprocreuse | ||||
| lfs2_remove singleprocreuse | ||||
|     for (int c = 0; c < CYCLES; c++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
| echo "--- Exhaustion test ---" | ||||
| scripts/test.py << TEST | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_file_open(&lfs2, &files[n], path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|         } | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs2_file_write(&lfs2, &files[n], names[n], size) => size; | ||||
|             } | ||||
|         } | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             lfs2_file_close(&lfs2, &files[n]) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|                 assert(memcmp(buffer, names[n], size) == 0); | ||||
|             } | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|         lfs2_remove(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
| 
 | ||||
| [[case]] # serial allocation reuse test | ||||
| define.FILES = 3 | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-6)) / FILES)' | ||||
| define.CYCLES = [1, 10] | ||||
| code = ''' | ||||
|     const char *names[FILES] = {"bacon", "eggs", "pancakes"}; | ||||
| 
 | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     for (int c = 0; c < CYCLES; c++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             memcpy(buffer, names[n], size); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             } | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|         } | ||||
| 
 | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             size = strlen(names[n]); | ||||
|             for (int i = 0; i < SIZE; i += size) { | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|                 assert(memcmp(buffer, names[n], size) == 0); | ||||
|             } | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int n = 0; n < FILES; n++) { | ||||
|             sprintf(path, "breakfast/%s", names[n]); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|         lfs2_remove(&lfs2, "breakfast") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
| 
 | ||||
| [[case]] # exhaustion test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     lfs2_size_t size = strlen("exhaustion"); | ||||
|     size = strlen("exhaustion"); | ||||
|     memcpy(buffer, "exhaustion", size); | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
| @@ -141,27 +215,27 @@ scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY); | ||||
|     lfs2_size_t size = strlen("exhaustion"); | ||||
|     size = strlen("exhaustion"); | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "exhaustion", size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Exhaustion wraparound test ---" | ||||
| scripts/test.py << TEST | ||||
| [[case]] # exhaustion wraparound test | ||||
| define.SIZE = '(((LFS2_BLOCK_SIZE-8)*(LFS2_BLOCK_COUNT-4)) / 3)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
| 
 | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     lfs2_size_t size = strlen("buffering"); | ||||
|     size = strlen("buffering"); | ||||
|     memcpy(buffer, "buffering", size); | ||||
|     for (int i = 0; i < $SIZE; i++) { | ||||
|     for (int i = 0; i < SIZE; i += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| @@ -188,30 +262,29 @@ scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_RDONLY); | ||||
|     lfs2_size_t size = strlen("exhaustion"); | ||||
|     size = strlen("exhaustion"); | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "exhaustion", size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Dir exhaustion test ---" | ||||
| scripts/test.py << TEST | ||||
| [[case]] # dir exhaustion test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     // find out max file size | ||||
|     lfs2_mkdir(&lfs2, "exhaustiondir") => 0; | ||||
|     lfs2_size_t size = strlen("blahblahblahblah"); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     int count = 0; | ||||
|     int err; | ||||
|     while (true) { | ||||
|         err = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (err < 0) { | ||||
| @@ -248,18 +321,102 @@ scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_remove(&lfs2, "exhaustion") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| ## Below, these tests depend _very_ heavily on the geometry of the | ||||
| ## block device being tested, they should be removed and replaced | ||||
| ## by generalized tests. For now we'll just skip if the geometry | ||||
| ## is customized. | ||||
| [[case]] # what if we have a bad block during an allocation scan? | ||||
| in = "lfs2.c" | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = 'LFS2_TESTBD_BADBLOCK_READERROR' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     // first fill to exhaustion to find available space | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     lfs2_size_t filesize = 0; | ||||
|     while (true) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC); | ||||
|         if (res == LFS2_ERR_NOSPC) { | ||||
|             break; | ||||
|         } | ||||
|         filesize += size; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // now fill all but a couple of blocks of the filesystem with data | ||||
|     filesize -= 3*LFS2_BLOCK_SIZE; | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     for (lfs2_size_t i = 0; i < filesize/size; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // also save head of file so we can error during lookahead scan | ||||
|     lfs2_block_t fileblock = file.ctz.head; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
| if [[ ! $MAKEFLAGS =~ "LFS2_BLOCK_CYCLES" ]] | ||||
| then | ||||
|     // remount to force an alloc scan | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
| echo "--- Chained dir exhaustion test ---" | ||||
| scripts/test.py << TEST | ||||
|     // but mark the head of our file as a "bad block", this is force our | ||||
|     // scan to bail early | ||||
|     lfs2_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "chomp"); | ||||
|     size = strlen("chomp"); | ||||
|     while (true) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_CORRUPT); | ||||
|         if (res == LFS2_ERR_CORRUPT) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     // now reverse the "bad block" and try to write the file again until we | ||||
|     // run out of space | ||||
|     lfs2_testbd_setwear(&cfg, fileblock, 0) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "ghost", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     strcpy((char*)buffer, "chomp"); | ||||
|     size = strlen("chomp"); | ||||
|     while (true) { | ||||
|         lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         assert(res == (lfs2_ssize_t)size || res == LFS2_ERR_NOSPC); | ||||
|         if (res == LFS2_ERR_NOSPC) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|     // check that the disk isn't hurt | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "pacman", LFS2_O_RDONLY) => 0; | ||||
|     strcpy((char*)buffer, "waka"); | ||||
|     size = strlen("waka"); | ||||
|     for (lfs2_size_t i = 0; i < filesize/size; i++) { | ||||
|         uint8_t rbuffer[4]; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| 
 | ||||
| 
 | ||||
| # Below, I don't like these tests. They're fragile and depend _heavily_ | ||||
| # on the geometry of the block device. But they are valuable. Eventually they | ||||
| # should be removed and replaced with generalized tests. | ||||
| 
 | ||||
| [[case]] # chained dir exhaustion test | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     // find out max file size | ||||
| @@ -268,11 +425,10 @@ scripts/test.py << TEST | ||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_size_t size = strlen("blahblahblahblah"); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     int count = 0; | ||||
|     int err; | ||||
|     while (true) { | ||||
|         err = lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         if (err < 0) { | ||||
| @@ -324,13 +480,14 @@ scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Split dir test ---" | ||||
| scripts/test.py << TEST | ||||
| [[case]] # split dir test | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     // create one block hole for half a directory | ||||
| @@ -342,7 +499,7 @@ scripts/test.py << TEST | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion", LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|     lfs2_size_t size = strlen("blahblahblahblah"); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < (cfg.block_count-4)*(cfg.block_size-8); | ||||
| @@ -368,18 +525,20 @@ scripts/test.py << TEST | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Outdated lookahead test ---" | ||||
| scripts/test.py << TEST | ||||
| [[case]] # outdated lookahead test | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     // fill completely with two files | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_size_t size = strlen("blahblahblahblah"); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); | ||||
| @@ -429,18 +588,22 @@ scripts/test.py << TEST | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| TEST | ||||
| 
 | ||||
| echo "--- Outdated lookahead and split dir test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| 
 | ||||
| [[case]] # outdated lookahead and split dir test | ||||
| define.LFS2_BLOCK_SIZE = 512 | ||||
| define.LFS2_BLOCK_COUNT = 1024 | ||||
| if = 'LFS2_BLOCK_SIZE == 512 && LFS2_BLOCK_COUNT == 1024' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     // fill completely with two files | ||||
|     lfs2_file_open(&lfs2, &file, "exhaustion1", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_size_t size = strlen("blahblahblahblah"); | ||||
|     size = strlen("blahblahblahblah"); | ||||
|     memcpy(buffer, "blahblahblahblah", size); | ||||
|     for (lfs2_size_t i = 0; | ||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); | ||||
| @@ -487,8 +650,4 @@ scripts/test.py << TEST | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| 
 | ||||
| fi | ||||
| 
 | ||||
| scripts/results.py | ||||
| ''' | ||||
							
								
								
									
										84
									
								
								tests/test_attrs.sh → tests/test_attrs.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										84
									
								
								tests/test_attrs.sh → tests/test_attrs.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @@ -1,25 +1,13 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
| 
 | ||||
| echo "=== Attr tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
| [[case]] # set/get attribute | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) | ||||
|             => strlen("hello"); | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| 
 | ||||
| echo "--- Set/get attribute ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs2_setattr(&lfs2, "hello", 'A', "aaaa",   4) => 0; | ||||
| @@ -71,8 +59,7 @@ scripts/test.py << TEST | ||||
|     lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5; | ||||
| 
 | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs2_getattr(&lfs2, "hello", 'A', buffer,    4) => 4; | ||||
| @@ -87,10 +74,18 @@ scripts/test.py << TEST | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| [[case]] # set/get root attribute | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
| echo "--- Set/get root attribute ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs2_setattr(&lfs2, "/", 'A', "aaaa",   4) => 0; | ||||
| @@ -141,8 +136,7 @@ scripts/test.py << TEST | ||||
|     lfs2_getattr(&lfs2, "/", 'B', buffer+4,  6) => 9; | ||||
|     lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     lfs2_getattr(&lfs2, "/", 'A', buffer,    4) => 4; | ||||
| @@ -157,10 +151,18 @@ scripts/test.py << TEST | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| [[case]] # set/get file attribute | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
| echo "--- Set/get file attribute ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs2_attr attrs1[] = { | ||||
| @@ -235,18 +237,17 @@ scripts/test.py << TEST | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| 
 | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs2_attr attrs2[] = { | ||||
|     struct lfs2_attr attrs3[] = { | ||||
|         {'A', buffer,    4}, | ||||
|         {'B', buffer+4,  9}, | ||||
|         {'C', buffer+13, 5}, | ||||
|     }; | ||||
|     struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||
|     struct lfs2_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; | ||||
| 
 | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg2) => 0; | ||||
|     lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg3) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
| @@ -257,11 +258,22 @@ scripts/test.py << TEST | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| ''' | ||||
| 
 | ||||
| echo "--- Deferred file attributes ---" | ||||
| scripts/test.py << TEST | ||||
| [[case]] # deferred file attributes | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello"); | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| 
 | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_setattr(&lfs2, "hello/hello", 'B', "fffffffff",  9) => 0; | ||||
|     lfs2_setattr(&lfs2, "hello/hello", 'C', "ccccc",      5) => 0; | ||||
| 
 | ||||
|     memset(buffer, 0, sizeof(buffer)); | ||||
|     struct lfs2_attr attrs1[] = { | ||||
|         {'B', "gggg", 4}, | ||||
| @@ -289,6 +301,4 @@ scripts/test.py << TEST | ||||
| 
 | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| 
 | ||||
| scripts/results.py | ||||
| ''' | ||||
							
								
								
									
										241
									
								
								tests/test_badblocks.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								tests/test_badblocks.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| # bad blocks with block cycles should be tested in test_relocations | ||||
| if = 'LFS2_BLOCK_CYCLES == -1' | ||||
|  | ||||
| [[case]] # single bad blocks | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs2_block_t badblock = 2; badblock < LFS2_BLOCK_COUNT; badblock++) { | ||||
|         lfs2_testbd_setwear(&cfg, badblock-1, 0) => 0; | ||||
|         lfs2_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; | ||||
|          | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int i = 1; i < 10; i++) { | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j] = '0'+i; | ||||
|             } | ||||
|             buffer[NAMEMULT] = '\0'; | ||||
|             lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|             buffer[NAMEMULT] = '/'; | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j+NAMEMULT+1] = '0'+i; | ||||
|             } | ||||
|             buffer[2*NAMEMULT+1] = '\0'; | ||||
|             lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|              | ||||
|             size = NAMEMULT; | ||||
|             for (int j = 0; j < i*FILEMULT; j++) { | ||||
|                 lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             } | ||||
|  | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (int i = 1; i < 10; i++) { | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j] = '0'+i; | ||||
|             } | ||||
|             buffer[NAMEMULT] = '\0'; | ||||
|             lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|             info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|             buffer[NAMEMULT] = '/'; | ||||
|             for (int j = 0; j < NAMEMULT; j++) { | ||||
|                 buffer[j+NAMEMULT+1] = '0'+i; | ||||
|             } | ||||
|             buffer[2*NAMEMULT+1] = '\0'; | ||||
|             lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|              | ||||
|             size = NAMEMULT; | ||||
|             for (int j = 0; j < i*FILEMULT; j++) { | ||||
|                 uint8_t rbuffer[1024]; | ||||
|                 lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|                 memcmp(buffer, rbuffer, size) => 0; | ||||
|             } | ||||
|  | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| [[case]] # region corruption (causes cascading failures) | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs2_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; | ||||
|     } | ||||
|      | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             uint8_t rbuffer[1024]; | ||||
|             lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|             memcmp(buffer, rbuffer, size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # alternating corruption (causes cascading failures) | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.NAMEMULT = 64 | ||||
| define.FILEMULT = 1 | ||||
| code = ''' | ||||
|     for (lfs2_block_t i = 0; i < (LFS2_BLOCK_COUNT-2)/2; i++) { | ||||
|         lfs2_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; | ||||
|     } | ||||
|      | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[NAMEMULT] = '\0'; | ||||
|         lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|         buffer[NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < NAMEMULT; j++) { | ||||
|             buffer[j+NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|          | ||||
|         size = NAMEMULT; | ||||
|         for (int j = 0; j < i*FILEMULT; j++) { | ||||
|             uint8_t rbuffer[1024]; | ||||
|             lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|             memcmp(buffer, rbuffer, size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| # other corner cases | ||||
| [[case]] # bad superblocks (corrupt 1 or 0) | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_ERASE_VALUE = [0x00, 0xff, -1] | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| code = ''' | ||||
|     lfs2_testbd_setwear(&cfg, 0, 0xffffffff) => 0; | ||||
|     lfs2_testbd_setwear(&cfg, 1, 0xffffffff) => 0; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => LFS2_ERR_NOSPC; | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
| @@ -1,120 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Corrupt tests ===" | ||||
|  | ||||
| NAMEMULT=64 | ||||
| FILEMULT=1 | ||||
|  | ||||
| lfs2_mktree() { | ||||
| scripts/test.py ${1:-} << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < $NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[$NAMEMULT] = '\0'; | ||||
|         lfs2_mkdir(&lfs2, (char*)buffer) => 0; | ||||
|  | ||||
|         buffer[$NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < $NAMEMULT; j++) { | ||||
|             buffer[j+$NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*$NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|          | ||||
|         lfs2_size_t size = $NAMEMULT; | ||||
|         for (int j = 0; j < i*$FILEMULT; j++) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| lfs2_chktree() { | ||||
| scripts/test.py ${1:-} << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 1; i < 10; i++) { | ||||
|         for (int j = 0; j < $NAMEMULT; j++) { | ||||
|             buffer[j] = '0'+i; | ||||
|         } | ||||
|         buffer[$NAMEMULT] = '\0'; | ||||
|         lfs2_stat(&lfs2, (char*)buffer, &info) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|  | ||||
|         buffer[$NAMEMULT] = '/'; | ||||
|         for (int j = 0; j < $NAMEMULT; j++) { | ||||
|             buffer[j+$NAMEMULT+1] = '0'+i; | ||||
|         } | ||||
|         buffer[2*$NAMEMULT+1] = '\0'; | ||||
|         lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0; | ||||
|          | ||||
|         lfs2_size_t size = $NAMEMULT; | ||||
|         for (int j = 0; j < i*$FILEMULT; j++) { | ||||
|             uint8_t rbuffer[1024]; | ||||
|             lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|             memcmp(buffer, rbuffer, size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| echo "--- Sanity check ---" | ||||
| rm -rf blocks | ||||
| lfs2_mktree | ||||
| lfs2_chktree | ||||
| BLOCKS="$(ls blocks | grep -vw '[01]')" | ||||
|  | ||||
| echo "--- Block corruption ---" | ||||
| for b in $BLOCKS | ||||
| do  | ||||
|     rm -rf blocks | ||||
|     mkdir blocks | ||||
|     ln -s /dev/zero blocks/$b | ||||
|     lfs2_mktree | ||||
|     lfs2_chktree | ||||
| done | ||||
|  | ||||
| echo "--- Block persistance ---" | ||||
| for b in $BLOCKS | ||||
| do  | ||||
|     rm -rf blocks | ||||
|     mkdir blocks | ||||
|     lfs2_mktree | ||||
|     chmod a-w blocks/$b || true | ||||
|     lfs2_mktree | ||||
|     lfs2_chktree | ||||
| done | ||||
|  | ||||
| echo "--- Big region corruption ---" | ||||
| rm -rf blocks | ||||
| mkdir blocks | ||||
| for i in {2..512} | ||||
| do | ||||
|     ln -s /dev/zero blocks/$(printf '%x' $i) | ||||
| done | ||||
| lfs2_mktree | ||||
| lfs2_chktree | ||||
|  | ||||
| echo "--- Alternating corruption ---" | ||||
| rm -rf blocks | ||||
| mkdir blocks | ||||
| for i in {2..1024..2} | ||||
| do | ||||
|     ln -s /dev/zero blocks/$(printf '%x' $i) | ||||
| done | ||||
| lfs2_mktree | ||||
| lfs2_chktree | ||||
|  | ||||
| scripts/results.py | ||||
| @@ -1,489 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Directory tests ===" | ||||
|  | ||||
| LARGESIZE=128 | ||||
|  | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Root directory ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Directory creation ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- File creation ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "burito", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Directory iteration ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "potato") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Directory failures ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato") => LFS2_ERR_EXIST; | ||||
|     lfs2_dir_open(&lfs2, &dir, "tomato") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "burito") => LFS2_ERR_NOTDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "tomato", LFS2_O_RDONLY) => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "potato", LFS2_O_RDONLY) => LFS2_ERR_ISDIR; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Nested directories ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/baked") => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/sweet") => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/fried") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "potato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "baked") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "fried") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "sweet") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block directory ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "cactus") => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "cactus/test%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "cactus") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Directory remove ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "potato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "potato/sweet") => 0; | ||||
|     lfs2_remove(&lfs2, "potato/baked") => 0; | ||||
|     lfs2_remove(&lfs2, "potato/fried") => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "potato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "potato") => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "cactus") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "cactus") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Directory rename ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato/baked") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato/sweet") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato/fried") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "coldpotato", "hotpotato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "hotpotato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "baked") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "fried") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "sweet") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "warmpotato") => 0; | ||||
|     lfs2_mkdir(&lfs2, "warmpotato/mushy") => 0; | ||||
|     lfs2_rename(&lfs2, "hotpotato", "warmpotato") => LFS2_ERR_NOTEMPTY; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "warmpotato/mushy") => 0; | ||||
|     lfs2_rename(&lfs2, "hotpotato", "warmpotato") => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "warmpotato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "baked") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "fried") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "sweet") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato") => 0; | ||||
|     lfs2_rename(&lfs2, "warmpotato/baked", "coldpotato/baked") => 0; | ||||
|     lfs2_rename(&lfs2, "warmpotato/sweet", "coldpotato/sweet") => 0; | ||||
|     lfs2_rename(&lfs2, "warmpotato/fried", "coldpotato/fried") => 0; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "warmpotato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "coldpotato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "baked") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "fried") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "sweet") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Recursive remove ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "coldpotato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|  | ||||
|     while (true) { | ||||
|         int err = lfs2_dir_read(&lfs2, &dir, &info); | ||||
|         err >= 0 => 1; | ||||
|         if (err == 0) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         strcpy(path, "coldpotato/"); | ||||
|         strcat(path, info.name); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "coldpotato") => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "cactus") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block rename ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         char oldpath[1024]; | ||||
|         char newpath[1024]; | ||||
|         sprintf(oldpath, "cactus/test%03d", i); | ||||
|         sprintf(newpath, "cactus/tedd%03d", i); | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "cactus") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "tedd%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         info.type => LFS2_TYPE_DIR; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block remove ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "cactus") => LFS2_ERR_NOTEMPTY; | ||||
|  | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "cactus/tedd%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "cactus") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block directory with files ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "prickly-pear") => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "prickly-pear/test%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|         lfs2_size_t size = 6; | ||||
|         memcpy(buffer, "Hello", size); | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         info.type => LFS2_TYPE_REG; | ||||
|         info.size => 6; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block rename with files ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         char oldpath[1024]; | ||||
|         char newpath[1024]; | ||||
|         sprintf(oldpath, "prickly-pear/test%03d", i); | ||||
|         sprintf(newpath, "prickly-pear/tedd%03d", i); | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "tedd%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         info.type => LFS2_TYPE_REG; | ||||
|         info.size => 6; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Multi-block remove with files ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => LFS2_ERR_NOTEMPTY; | ||||
|  | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "prickly-pear/tedd%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "burito") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										838
									
								
								tests/test_dirs.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										838
									
								
								tests/test_dirs.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,838 @@ | ||||
| [[case]] # root | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many directory creation | ||||
| define.N = 'range(0, 100, 3)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "dir%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "dir%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many directory removal | ||||
| define.N = 'range(3, 100, 11)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many directory rename | ||||
| define.N = 'range(3, 100, 11)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         char oldpath[128]; | ||||
|         char newpath[128]; | ||||
|         sprintf(oldpath, "test%03d", i); | ||||
|         sprintf(newpath, "tedd%03d", i); | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "tedd%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant many directory creation/rename/removal | ||||
| define.N = [5, 11] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         err = lfs2_mkdir(&lfs2, path); | ||||
|         assert(err == 0 || err == LFS2_ERR_EXIST); | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         err = lfs2_remove(&lfs2, path); | ||||
|         assert(err == 0 || err == LFS2_ERR_NOENT); | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         char oldpath[128]; | ||||
|         char newpath[128]; | ||||
|         sprintf(oldpath, "hi%03d", i); | ||||
|         sprintf(newpath, "hello%03d", i); | ||||
|         // YES this can overwrite an existing newpath | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # file creation | ||||
| define.N = 'range(3, 100, 11)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
| ''' | ||||
|  | ||||
| [[case]] # file removal | ||||
| define.N = 'range(0, 100, 3)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "removeme%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # file rename | ||||
| define.N = 'range(0, 100, 3)' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "test%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         char oldpath[128]; | ||||
|         char newpath[128]; | ||||
|         sprintf(oldpath, "test%03d", i); | ||||
|         sprintf(newpath, "tedd%03d", i); | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "tedd%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant file creation/rename/removal | ||||
| define.N = [5, 25] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         err = lfs2_remove(&lfs2, path); | ||||
|         assert(err == 0 || err == LFS2_ERR_NOENT); | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         char oldpath[128]; | ||||
|         char newpath[128]; | ||||
|         sprintf(oldpath, "hi%03d", i); | ||||
|         sprintf(newpath, "hello%03d", i); | ||||
|         // YES this can overwrite an existing newpath | ||||
|         lfs2_rename(&lfs2, oldpath, newpath) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "hello%03d", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # nested directories | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "burito", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/baked") => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/sweet") => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato/fried") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "potato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "baked") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "fried") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "sweet") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // try removing? | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "potato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // try renaming? | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "potato", "coldpotato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "coldpotato", "warmpotato") => 0; | ||||
|     lfs2_rename(&lfs2, "warmpotato", "hotpotato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "potato") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "warmpotato") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // try cross-directory renaming | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coldpotato") => 0; | ||||
|     lfs2_rename(&lfs2, "hotpotato/baked", "coldpotato/baked") => 0; | ||||
|     lfs2_rename(&lfs2, "coldpotato", "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_rename(&lfs2, "hotpotato/fried", "coldpotato/fried") => 0; | ||||
|     lfs2_rename(&lfs2, "coldpotato", "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_rename(&lfs2, "hotpotato/sweet", "coldpotato/sweet") => 0; | ||||
|     lfs2_rename(&lfs2, "coldpotato", "hotpotato") => 0; | ||||
|     lfs2_remove(&lfs2, "coldpotato") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "hotpotato") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "baked") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "fried") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "sweet") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|      | ||||
|     // final remove | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "hotpotato/baked") => 0; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "hotpotato/fried") => 0; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => LFS2_ERR_NOTEMPTY; | ||||
|     lfs2_remove(&lfs2, "hotpotato/sweet") => 0; | ||||
|     lfs2_remove(&lfs2, "hotpotato") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "burito") == 0); | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # recursive remove | ||||
| define.N = [10, 100] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "prickly-pear") => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "prickly-pear/cactus%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "cactus%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2); | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => LFS2_ERR_NOTEMPTY; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "cactus%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         sprintf(path, "prickly-pear/%s", info.name); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => 0; | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_remove(&lfs2, "prickly-pear") => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # other error cases | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "potato") => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "burito", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "potato") => LFS2_ERR_EXIST; | ||||
|     lfs2_mkdir(&lfs2, "burito") => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "burito", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "potato", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => LFS2_ERR_EXIST; | ||||
|     lfs2_dir_open(&lfs2, &dir, "tomato") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "burito") => LFS2_ERR_NOTDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "tomato", LFS2_O_RDONLY) => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "potato", LFS2_O_RDONLY) => LFS2_ERR_ISDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "tomato", LFS2_O_WRONLY) => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "potato", LFS2_O_WRONLY) => LFS2_ERR_ISDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "potato", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_ISDIR; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "/", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "/", LFS2_O_RDONLY) => LFS2_ERR_ISDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "/", LFS2_O_WRONLY) => LFS2_ERR_ISDIR; | ||||
|     lfs2_file_open(&lfs2, &file, "/", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_ISDIR; | ||||
|  | ||||
|     // check that errors did not corrupt directory | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(strcmp(info.name, "burito") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "potato") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // or on disk | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(strcmp(info.name, "burito") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "potato") == 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # directory seek | ||||
| define.COUNT = [4, 128, 132] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hello/kitty%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     for (int j = 2; j < COUNT; j++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_dir_open(&lfs2, &dir, "hello") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, ".") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, "..") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_soff_t pos; | ||||
|         for (int i = 0; i < j; i++) { | ||||
|             sprintf(path, "kitty%03d", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             assert(strcmp(info.name, path) == 0); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|             pos = lfs2_dir_tell(&lfs2, &dir); | ||||
|             assert(pos >= 0); | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|         sprintf(path, "kitty%03d", j); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         sprintf(path, "kitty%03d", 0); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, ".") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, "..") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|         sprintf(path, "kitty%03d", j); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| [[case]] # root seek | ||||
| define.COUNT = [4, 128, 132] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     for (int j = 2; j < COUNT; j++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, ".") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, "..") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_soff_t pos; | ||||
|         for (int i = 0; i < j; i++) { | ||||
|             sprintf(path, "hi%03d", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             assert(strcmp(info.name, path) == 0); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|             pos = lfs2_dir_tell(&lfs2, &dir); | ||||
|             assert(pos >= 0); | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|         sprintf(path, "hi%03d", j); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         sprintf(path, "hi%03d", 0); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, ".") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, "..") == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|         sprintf(path, "hi%03d", j); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
| ''' | ||||
|  | ||||
| @@ -1,251 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Entry tests ===" | ||||
|  | ||||
| # Note: These tests are intended for 512 byte inline size at different | ||||
| # inline sizes they should still pass, but won't be testing anything | ||||
|  | ||||
| rm -rf blocks | ||||
| function read_file { | ||||
| cat << TEST | ||||
|  | ||||
|     size = $2; | ||||
|     lfs2_file_open(&lfs2, &file, "$1", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| function write_file { | ||||
| cat << TEST | ||||
|  | ||||
|     size = $2; | ||||
|     lfs2_file_open(&lfs2, &file, "$1", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| echo "--- Entry grow test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 20) | ||||
|     $(write_file "hi1" 20) | ||||
|     $(write_file "hi2" 20) | ||||
|     $(write_file "hi3" 20) | ||||
|  | ||||
|     $(read_file "hi1" 20) | ||||
|     $(write_file "hi1" 200) | ||||
|  | ||||
|     $(read_file "hi0" 20) | ||||
|     $(read_file "hi1" 200) | ||||
|     $(read_file "hi2" 20) | ||||
|     $(read_file "hi3" 20) | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Entry shrink test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 20) | ||||
|     $(write_file "hi1" 200) | ||||
|     $(write_file "hi2" 20) | ||||
|     $(write_file "hi3" 20) | ||||
|  | ||||
|     $(read_file "hi1" 200) | ||||
|     $(write_file "hi1" 20) | ||||
|  | ||||
|     $(read_file "hi0" 20) | ||||
|     $(read_file "hi1" 20) | ||||
|     $(read_file "hi2" 20) | ||||
|     $(read_file "hi3" 20) | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Entry spill test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 200) | ||||
|     $(write_file "hi1" 200) | ||||
|     $(write_file "hi2" 200) | ||||
|     $(write_file "hi3" 200) | ||||
|  | ||||
|     $(read_file "hi0" 200) | ||||
|     $(read_file "hi1" 200) | ||||
|     $(read_file "hi2" 200) | ||||
|     $(read_file "hi3" 200) | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Entry push spill test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 200) | ||||
|     $(write_file "hi1" 20) | ||||
|     $(write_file "hi2" 200) | ||||
|     $(write_file "hi3" 200) | ||||
|  | ||||
|     $(read_file "hi1" 20) | ||||
|     $(write_file "hi1" 200) | ||||
|  | ||||
|     $(read_file "hi0" 200) | ||||
|     $(read_file "hi1" 200) | ||||
|     $(read_file "hi2" 200) | ||||
|     $(read_file "hi3" 200) | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Entry push spill two test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 200) | ||||
|     $(write_file "hi1" 20) | ||||
|     $(write_file "hi2" 200) | ||||
|     $(write_file "hi3" 200) | ||||
|     $(write_file "hi4" 200) | ||||
|  | ||||
|     $(read_file "hi1" 20) | ||||
|     $(write_file "hi1" 200) | ||||
|  | ||||
|     $(read_file "hi0" 200) | ||||
|     $(read_file "hi1" 200) | ||||
|     $(read_file "hi2" 200) | ||||
|     $(read_file "hi3" 200) | ||||
|     $(read_file "hi4" 200) | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Entry drop test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_size_t size; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     $(write_file "hi0" 200) | ||||
|     $(write_file "hi1" 200) | ||||
|     $(write_file "hi2" 200) | ||||
|     $(write_file "hi3" 200) | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi1") => 0; | ||||
|     lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT; | ||||
|     $(read_file "hi0" 200) | ||||
|     $(read_file "hi2" 200) | ||||
|     $(read_file "hi3" 200) | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi2") => 0; | ||||
|     lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT; | ||||
|     $(read_file "hi0" 200) | ||||
|     $(read_file "hi3" 200) | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi3") => 0; | ||||
|     lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT; | ||||
|     $(read_file "hi0" 200) | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi0") => 0; | ||||
|     lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Create too big ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     lfs2_size_t size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Resize too big ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     lfs2_size_t size = 40; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 40; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										611
									
								
								tests/test_entries.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										611
									
								
								tests/test_entries.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,611 @@ | ||||
| # These tests are for some specific corner cases with neighboring inline files. | ||||
| # Note that these tests are intended for 512 byte inline sizes. They should | ||||
| # still pass with other inline sizes but wouldn't be testing anything. | ||||
|  | ||||
| define.LFS2_CACHE_SIZE = 512 | ||||
| if = 'LFS2_CACHE_SIZE % LFS2_PROG_SIZE == 0 && LFS2_CACHE_SIZE == 512' | ||||
|  | ||||
| [[case]] # entry grow test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry shrink test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 20 | ||||
|     sprintf(path, "hi0"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 20 | ||||
|     sprintf(path, "hi2"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 20 | ||||
|     sprintf(path, "hi3"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry spill test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry push spill test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry push spill two test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi4 200 | ||||
|     sprintf(path, "hi4"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi1 20 | ||||
|     sprintf(path, "hi1"); size = 20; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi4 200 | ||||
|     sprintf(path, "hi4"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # entry drop test | ||||
| code = ''' | ||||
|     uint8_t wbuffer[1024]; | ||||
|     uint8_t rbuffer[1024]; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi1 200 | ||||
|     sprintf(path, "hi1"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // write hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi1") => 0; | ||||
|     lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi2 200 | ||||
|     sprintf(path, "hi2"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi2") => 0; | ||||
|     lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // read hi3 200 | ||||
|     sprintf(path, "hi3"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi3") => 0; | ||||
|     lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT; | ||||
|     // read hi0 200 | ||||
|     sprintf(path, "hi0"); size = 200; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "hi0") => 0; | ||||
|     lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # create too big | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # resize too big | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'm', 200); | ||||
|     path[200] = '\0'; | ||||
|  | ||||
|     size = 40; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 40; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     memset(wbuffer, 'c', size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     size = 400; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
							
								
								
									
										288
									
								
								tests/test_evil.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								tests/test_evil.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,288 @@ | ||||
| # Tests for recovering from conditions which shouldn't normally | ||||
| # happen during normal operation of littlefs | ||||
|  | ||||
| # invalid pointer tests (outside of block_count) | ||||
|  | ||||
| [[case]] # invalid tail-pointer test | ||||
| define.TAIL_TYPE = ['LFS2_TYPE_HARDTAIL', 'LFS2_TYPE_SOFTTAIL'] | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // change tail-pointer to invalid pointers | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){ | ||||
|                     (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|                     (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid dir pointer test | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a dir | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "dir_here") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // change the dir pointer to be invalid | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our directory | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("dir_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIR, 1, strlen("dir_here")); | ||||
|     assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0); | ||||
|     // change dir pointer | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, 8), | ||||
|                 (lfs2_block_t[2]){ | ||||
|                     (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|                     (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad dir fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dir_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "dir_here") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_stat(&lfs2, "dir_here/file_here", &info) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "dir_here/dir_here") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_open(&lfs2, &file, "dir_here/file_here", | ||||
|             LFS2_O_RDONLY) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_open(&lfs2, &file, "dir_here/file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid file pointer test | ||||
| in = "lfs2.c" | ||||
| define.SIZE = [10, 1000, 100000] # faked file size | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a file | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // change the file pointer to be invalid | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our file | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here")); | ||||
|     assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); | ||||
|     // change file pointer | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)), | ||||
|                 &(struct lfs2_ctz){0xcccccccc, lfs2_tole32(SIZE)}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad file fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "file_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "file_here") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // any allocs that traverse CTZ must unfortunately must fail | ||||
|     if (SIZE > 2*LFS2_BLOCK_SIZE) { | ||||
|         lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid pointer in CTZ skip-list test | ||||
| define.SIZE = ['2*LFS2_BLOCK_SIZE', '3*LFS2_BLOCK_SIZE', '4*LFS2_BLOCK_SIZE'] | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // make a file | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         char c = 'c'; | ||||
|         lfs2_file_write(&lfs2, &file, &c, 1) => 1; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     // change pointer in CTZ skip-list to be invalid | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     // make sure id 1 == our file and get our CTZ structure | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here")); | ||||
|     assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); | ||||
|     struct lfs2_ctz ctz; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x700, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_STRUCT, 1, sizeof(struct lfs2_ctz)), &ctz) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)); | ||||
|     lfs2_ctz_fromle32(&ctz); | ||||
|     // rewrite block to contain bad pointer | ||||
|     uint8_t bbuffer[LFS2_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     uint32_t bad = lfs2_tole32(0xcccccccc); | ||||
|     memcpy(&bbuffer[0], &bad, sizeof(bad)); | ||||
|     memcpy(&bbuffer[4], &bad, sizeof(bad)); | ||||
|     cfg.erase(&cfg, ctz.head) => 0; | ||||
|     cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that accessing our bad file fails, note there's a number | ||||
|     // of ways to access the dir, some can fail, but some don't | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "file_here", &info) => 0; | ||||
|     assert(strcmp(info.name, "file_here") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // any allocs that traverse CTZ must unfortunately must fail | ||||
|     if (SIZE > 2*LFS2_BLOCK_SIZE) { | ||||
|         lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
|  | ||||
| [[case]] # invalid gstate pointer | ||||
| define.INVALSET = [0x3, 0x1, 0x2] | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // create an invalid gstate | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_fs_prepmove(&lfs2, 1, (lfs2_block_t [2]){ | ||||
|             (INVALSET & 0x1) ? 0xcccccccc : 0, | ||||
|             (INVALSET & 0x2) ? 0xcccccccc : 0}); | ||||
|     lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     // mount may not fail, but our first alloc should fail when | ||||
|     // we try to fix the gstate | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "should_fail") => LFS2_ERR_CORRUPT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| # cycle detection/recovery tests | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list loop test | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // change tail-pointer to point to ourself | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){0, 1}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list 2-length loop test | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs with child dir | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // find child | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_block_t pair[2]; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs2_pair_fromle32(pair); | ||||
|     // change tail-pointer to point to root | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, pair) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), | ||||
|                 (lfs2_block_t[2]){0, 1}})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # metadata-pair threaded-list 1-length child loop test | ||||
| in = "lfs2.c" | ||||
| code = ''' | ||||
|     // create littlefs with child dir | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // find child | ||||
|     lfs2_init(&lfs2, &cfg) => 0; | ||||
|     lfs2_mdir_t mdir; | ||||
|     lfs2_block_t pair[2]; | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0; | ||||
|     lfs2_dir_get(&lfs2, &mdir, | ||||
|             LFS2_MKTAG(0x7ff, 0x3ff, 0), | ||||
|             LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) | ||||
|                 => LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)); | ||||
|     lfs2_pair_fromle32(pair); | ||||
|     // change tail-pointer to point to ourself | ||||
|     lfs2_dir_fetch(&lfs2, &mdir, pair) => 0; | ||||
|     lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS( | ||||
|             {LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; | ||||
|     lfs2_deinit(&lfs2) => 0; | ||||
|  | ||||
|     // test that mount fails gracefully | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
							
								
								
									
										465
									
								
								tests/test_exhaustion.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								tests/test_exhaustion.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | ||||
| [[case]] # test running a filesystem to exhaustion | ||||
| define.LFS2_ERASE_CYCLES = 10 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (true) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "roadrunner/test%d", i); | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
| ''' | ||||
|  | ||||
| [[case]] # test running a filesystem to exhaustion | ||||
|          # which also requires expanding superblocks | ||||
| define.LFS2_ERASE_CYCLES = 10 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.LFS2_BADBLOCK_BEHAVIOR = [ | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASEERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_READERROR', | ||||
|     'LFS2_TESTBD_BADBLOCK_PROGNOOP', | ||||
|     'LFS2_TESTBD_BADBLOCK_ERASENOOP', | ||||
| ] | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (true) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "test%d", i); | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
| ''' | ||||
|  | ||||
| # These are a sort of high-level litmus test for wear-leveling. One definition | ||||
| # of wear-leveling is that increasing a block device's space translates directly | ||||
| # into increasing the block devices lifetime. This is something we can actually | ||||
| # check for. | ||||
|  | ||||
| [[case]] # wear-level test running a filesystem to exhaustion | ||||
| define.LFS2_ERASE_CYCLES = 20 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     uint32_t run_cycles[2]; | ||||
|     const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT}; | ||||
|  | ||||
|     for (int run = 0; run < 2; run++) { | ||||
|         for (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) { | ||||
|             lfs2_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         uint32_t cycle = 0; | ||||
|         while (true) { | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // chose name, roughly random seed, and random 2^n size | ||||
|                 sprintf(path, "roadrunner/test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs2_file_open(&lfs2, &file, path, | ||||
|                         LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                     if (res == LFS2_ERR_NOSPC) { | ||||
|                         err = lfs2_file_close(&lfs2, &file); | ||||
|                         assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                         lfs2_unmount(&lfs2) => 0; | ||||
|                         goto exhausted; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 err = lfs2_file_close(&lfs2, &file); | ||||
|                 assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                 if (err == LFS2_ERR_NOSPC) { | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // check for errors | ||||
|                 sprintf(path, "roadrunner/test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     char r; | ||||
|                     lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                     assert(r == c); | ||||
|                 } | ||||
|  | ||||
|                 lfs2_file_close(&lfs2, &file) => 0; | ||||
|             } | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|             cycle += 1; | ||||
|         } | ||||
|  | ||||
| exhausted: | ||||
|         // should still be readable | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             lfs2_stat(&lfs2, path, &info) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         run_cycles[run] = cycle; | ||||
|         LFS2_WARN("completed %d blocks %d cycles", | ||||
|                 run_block_count[run], run_cycles[run]); | ||||
|     } | ||||
|  | ||||
|     // check we increased the lifetime by 2x with ~10% error | ||||
|     LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
| ''' | ||||
|  | ||||
| [[case]] # wear-level test + expanding superblock | ||||
| define.LFS2_ERASE_CYCLES = 20 | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = 'LFS2_ERASE_CYCLES / 2' | ||||
| define.FILES = 10 | ||||
| code = ''' | ||||
|     uint32_t run_cycles[2]; | ||||
|     const uint32_t run_block_count[2] = {LFS2_BLOCK_COUNT/2, LFS2_BLOCK_COUNT}; | ||||
|  | ||||
|     for (int run = 0; run < 2; run++) { | ||||
|         for (lfs2_block_t b = 0; b < LFS2_BLOCK_COUNT; b++) { | ||||
|             lfs2_testbd_setwear(&cfg, b, | ||||
|                     (b < run_block_count[run]) ? 0 : LFS2_ERASE_CYCLES) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|         uint32_t cycle = 0; | ||||
|         while (true) { | ||||
|             lfs2_mount(&lfs2, &cfg) => 0; | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // chose name, roughly random seed, and random 2^n size | ||||
|                 sprintf(path, "test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs2_file_open(&lfs2, &file, path, | ||||
|                         LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                     assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                     if (res == LFS2_ERR_NOSPC) { | ||||
|                         err = lfs2_file_close(&lfs2, &file); | ||||
|                         assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                         lfs2_unmount(&lfs2) => 0; | ||||
|                         goto exhausted; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 err = lfs2_file_close(&lfs2, &file); | ||||
|                 assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                 if (err == LFS2_ERR_NOSPC) { | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (uint32_t i = 0; i < FILES; i++) { | ||||
|                 // check for errors | ||||
|                 sprintf(path, "test%d", i); | ||||
|                 srand(cycle * i); | ||||
|                 size = 1 << ((rand() % 10)+2); | ||||
|  | ||||
|                 lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|                 for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                     char c = 'a' + (rand() % 26); | ||||
|                     char r; | ||||
|                     lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                     assert(r == c); | ||||
|                 } | ||||
|  | ||||
|                 lfs2_file_close(&lfs2, &file) => 0; | ||||
|             } | ||||
|             lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|             cycle += 1; | ||||
|         } | ||||
|  | ||||
| exhausted: | ||||
|         // should still be readable | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "test%d", i); | ||||
|             lfs2_stat(&lfs2, path, &info) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         run_cycles[run] = cycle; | ||||
|         LFS2_WARN("completed %d blocks %d cycles", | ||||
|                 run_block_count[run], run_cycles[run]); | ||||
|     } | ||||
|  | ||||
|     // check we increased the lifetime by 2x with ~10% error | ||||
|     LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
| ''' | ||||
|  | ||||
| [[case]] # test that we wear blocks roughly evenly | ||||
| define.LFS2_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS2_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS2_BLOCK_CYCLES = [5, 4, 3, 2, 1] | ||||
| define.CYCLES = 100 | ||||
| define.FILES = 10 | ||||
| if = 'LFS2_BLOCK_CYCLES < CYCLES/10' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "roadrunner") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (cycle < CYCLES) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, | ||||
|                     LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS2_ERR_NOSPC); | ||||
|                 if (res == LFS2_ERR_NOSPC) { | ||||
|                     err = lfs2_file_close(&lfs2, &file); | ||||
|                     assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|                     lfs2_unmount(&lfs2) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs2_file_close(&lfs2, &file); | ||||
|             assert(err == 0 || err == LFS2_ERR_NOSPC); | ||||
|             if (err == LFS2_ERR_NOSPC) { | ||||
|                 lfs2_unmount(&lfs2) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|             for (lfs2_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs2_file_read(&lfs2, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "roadrunner/test%d", i); | ||||
|         lfs2_stat(&lfs2, path, &info) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     LFS2_WARN("completed %d cycles", cycle); | ||||
|  | ||||
|     // check the wear on our block device | ||||
|     lfs2_testbd_wear_t minwear = -1; | ||||
|     lfs2_testbd_wear_t totalwear = 0; | ||||
|     lfs2_testbd_wear_t maxwear = 0; | ||||
|     // skip 0 and 1 as superblock movement is intentionally avoided | ||||
|     for (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) { | ||||
|         lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, b); | ||||
|         printf("%08x: wear %d\n", b, wear); | ||||
|         assert(wear >= 0); | ||||
|         if (wear < minwear) { | ||||
|             minwear = wear; | ||||
|         } | ||||
|         if (wear > maxwear) { | ||||
|             maxwear = wear; | ||||
|         } | ||||
|         totalwear += wear; | ||||
|     } | ||||
|     lfs2_testbd_wear_t avgwear = totalwear / LFS2_BLOCK_COUNT; | ||||
|     LFS2_WARN("max wear: %d cycles", maxwear); | ||||
|     LFS2_WARN("avg wear: %d cycles", totalwear / LFS2_BLOCK_COUNT); | ||||
|     LFS2_WARN("min wear: %d cycles", minwear); | ||||
|  | ||||
|     // find standard deviation^2 | ||||
|     lfs2_testbd_wear_t dev2 = 0; | ||||
|     for (lfs2_block_t b = 2; b < LFS2_BLOCK_COUNT; b++) { | ||||
|         lfs2_testbd_wear_t wear = lfs2_testbd_getwear(&cfg, b); | ||||
|         assert(wear >= 0); | ||||
|         lfs2_testbd_swear_t diff = wear - avgwear; | ||||
|         dev2 += diff*diff; | ||||
|     } | ||||
|     dev2 /= totalwear; | ||||
|     LFS2_WARN("std dev^2: %d", dev2); | ||||
|     assert(dev2 < 8); | ||||
| ''' | ||||
|  | ||||
| @@ -1,221 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== File tests ===" | ||||
|  | ||||
| SMALLSIZE=32 | ||||
| MEDIUMSIZE=8192 | ||||
| LARGESIZE=262144 | ||||
|  | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple file test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_size_t size = strlen("Hello World!\n"); | ||||
|     uint8_t wbuffer[1024]; | ||||
|     memcpy(wbuffer, "Hello World!\n", size); | ||||
|     lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "hello", LFS2_O_RDONLY) => 0; | ||||
|     size = strlen("Hello World!\n"); | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|     memcmp(rbuffer, wbuffer, size) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| w_test() { | ||||
| scripts/test.py ${4:-} << TEST | ||||
|     lfs2_size_t size = $1; | ||||
|     lfs2_size_t chunk = 31; | ||||
|     srand(0); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "$2", | ||||
|         ${3:-LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC}) => 0; | ||||
|     for (lfs2_size_t i = 0; i < size; i += chunk) { | ||||
|         chunk = (chunk < size - i) ? chunk : size - i; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| r_test() { | ||||
| scripts/test.py << TEST | ||||
|     lfs2_size_t size = $1; | ||||
|     lfs2_size_t chunk = 29; | ||||
|     srand(0); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "$2", &info) => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => size; | ||||
|     lfs2_file_open(&lfs2, &file, "$2", ${3:-LFS2_O_RDONLY}) => 0; | ||||
|     for (lfs2_size_t i = 0; i < size; i += chunk) { | ||||
|         chunk = (chunk < size - i) ? chunk : size - i; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk && i+b < size; b++) { | ||||
|             buffer[b] => rand() & 0xff; | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| echo "--- Small file test ---" | ||||
| w_test $SMALLSIZE smallavacado | ||||
| r_test $SMALLSIZE smallavacado | ||||
|  | ||||
| echo "--- Medium file test ---" | ||||
| w_test $MEDIUMSIZE mediumavacado | ||||
| r_test $MEDIUMSIZE mediumavacado | ||||
|  | ||||
| echo "--- Large file test ---" | ||||
| w_test $LARGESIZE largeavacado | ||||
| r_test $LARGESIZE largeavacado | ||||
|  | ||||
| echo "--- Zero file test ---" | ||||
| w_test 0 noavacado | ||||
| r_test 0 noavacado | ||||
|  | ||||
| echo "--- Truncate small test ---" | ||||
| w_test $SMALLSIZE mediumavacado | ||||
| r_test $SMALLSIZE mediumavacado | ||||
| w_test $MEDIUMSIZE mediumavacado | ||||
| r_test $MEDIUMSIZE mediumavacado | ||||
|  | ||||
| echo "--- Truncate zero test ---" | ||||
| w_test $SMALLSIZE noavacado | ||||
| r_test $SMALLSIZE noavacado | ||||
| w_test 0 noavacado | ||||
| r_test 0 noavacado | ||||
|  | ||||
| echo "--- Non-overlap check ---" | ||||
| r_test $SMALLSIZE smallavacado | ||||
| r_test $MEDIUMSIZE mediumavacado | ||||
| r_test $LARGESIZE largeavacado | ||||
| r_test 0 noavacado | ||||
|  | ||||
| echo "--- Dir check ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => strlen("Hello World!\n"); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "largeavacado") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => $LARGESIZE; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "mediumavacado") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => $MEDIUMSIZE; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "noavacado") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "smallavacado") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => $SMALLSIZE; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Many files test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     // Create 300 files of 7 bytes | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (unsigned i = 0; i < 300; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_size_t size = 7; | ||||
|         uint8_t wbuffer[1024]; | ||||
|         uint8_t rbuffer[1024]; | ||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         memcmp(wbuffer, rbuffer, size) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Many files with flush test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     // Create 300 files of 7 bytes | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (unsigned i = 0; i < 300; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_size_t size = 7; | ||||
|         uint8_t wbuffer[1024]; | ||||
|         uint8_t rbuffer[1024]; | ||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         memcmp(wbuffer, rbuffer, size) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Many files with power cycle test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     // Create 300 files of 7 bytes | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (unsigned i = 0; i < 300; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_size_t size = 7; | ||||
|         uint8_t wbuffer[1024]; | ||||
|         uint8_t rbuffer[1024]; | ||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         memcmp(wbuffer, rbuffer, size) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										486
									
								
								tests/test_files.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								tests/test_files.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,486 @@ | ||||
|  | ||||
| [[case]] # simple file test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     size = strlen("Hello World!")+1; | ||||
|     strcpy((char*)buffer, "Hello World!"); | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     assert(strcmp((char*)buffer, "Hello World!") == 0); | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # larger files | ||||
| define.SIZE = [32, 8192, 262144, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 33, 1, 1023] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # rewriting files | ||||
| define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // rewrite | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY) => 0; | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => lfs2_max(SIZE1, SIZE2); | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     if (SIZE1 > SIZE2) { | ||||
|         srand(1); | ||||
|         for (lfs2_size_t b = 0; b < SIZE2; b++) { | ||||
|             rand(); | ||||
|         } | ||||
|         for (lfs2_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { | ||||
|             lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|             lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|             for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|                 assert(buffer[b] == (rand() & 0xff)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # appending files | ||||
| define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // append | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_APPEND) => 0; | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1 + SIZE2; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncating files | ||||
| define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] | ||||
| define.CHUNKSIZE = [31, 16, 1] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     // write | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE1; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // truncate | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE2; | ||||
|     srand(2); | ||||
|     for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant file writing | ||||
| define.SIZE = [32, 0, 7, 2049] | ||||
| define.CHUNKSIZE = [31, 16, 65] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY); | ||||
|     assert(err == LFS2_ERR_NOENT || err == 0); | ||||
|     if (err == 0) { | ||||
|         // can only be 0 (new file) or full size | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size == 0 || size == SIZE); | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     // write | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant file writing with syncs | ||||
| define = [ | ||||
|     # append (O(n)) | ||||
|     {MODE='LFS2_O_APPEND',   SIZE=[32, 0, 7, 2049],  CHUNKSIZE=[31, 16, 65]}, | ||||
|     # truncate (O(n^2)) | ||||
|     {MODE='LFS2_O_TRUNC',    SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]}, | ||||
|     # rewrite (O(n^2)) | ||||
|     {MODE=0,                SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]}, | ||||
| ] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY); | ||||
|     assert(err == LFS2_ERR_NOENT || err == 0); | ||||
|     if (err == 0) { | ||||
|         // with syncs we could be any size, but it at least must be valid data | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size <= SIZE); | ||||
|         srand(1); | ||||
|         for (lfs2_size_t i = 0; i < size; i += CHUNKSIZE) { | ||||
|             lfs2_size_t chunk = lfs2_min(CHUNKSIZE, size-i); | ||||
|             lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|             for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|                 assert(buffer[b] == (rand() & 0xff)); | ||||
|             } | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     // write | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", | ||||
|         LFS2_O_WRONLY | LFS2_O_CREAT | MODE) => 0; | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     assert(size <= SIZE); | ||||
|     srand(1); | ||||
|     lfs2_size_t skip = (MODE == LFS2_O_APPEND) ? size : 0; | ||||
|     for (lfs2_size_t b = 0; b < skip; b++) { | ||||
|         rand(); | ||||
|     } | ||||
|     for (lfs2_size_t i = skip; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             buffer[b] = rand() & 0xff; | ||||
|         } | ||||
|         lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     // read | ||||
|     lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     srand(1); | ||||
|     for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) { | ||||
|         lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i); | ||||
|         lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk; | ||||
|         for (lfs2_size_t b = 0; b < chunk; b++) { | ||||
|             assert(buffer[b] == (rand() & 0xff)); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files | ||||
| define.N = 300 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // create N files of 7 bytes | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files with power cycle | ||||
| define.N = 300 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // create N files of 7 bytes | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # many files with power loss | ||||
| define.N = 300 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     // create N files of 7 bytes | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         sprintf(path, "file_%03d", i); | ||||
|         err = lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT); | ||||
|         char wbuffer[1024]; | ||||
|         size = 7; | ||||
|         snprintf(wbuffer, size, "Hi %03d", i); | ||||
|         if ((lfs2_size_t)lfs2_file_size(&lfs2, &file) != size) { | ||||
|             lfs2_file_write(&lfs2, &file, wbuffer, size) => size; | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|         char rbuffer[1024]; | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, rbuffer, size) => size; | ||||
|         assert(strcmp(rbuffer, wbuffer) == 0); | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| @@ -1,51 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Formatting tests ===" | ||||
| rm -rf blocks | ||||
|  | ||||
| echo "--- Basic formatting ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Basic mounting ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Invalid superblocks ---" | ||||
| ln -f -s /dev/zero blocks/0 | ||||
| ln -f -s /dev/zero blocks/1 | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => LFS2_ERR_NOSPC; | ||||
| TEST | ||||
| rm blocks/0 blocks/1 | ||||
|  | ||||
| echo "--- Invalid mount ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| TEST | ||||
|  | ||||
| echo "--- Expanding superblock ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < 100; i++) { | ||||
|         lfs2_mkdir(&lfs2, "dummy") => 0; | ||||
|         lfs2_remove(&lfs2, "dummy") => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "dummy") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
| @@ -1,190 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Interspersed tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Interspersed file test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_t files[4]; | ||||
|     lfs2_file_open(&lfs2, &files[0], "a", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "b", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[2], "c", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[3], "d", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"a", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"b", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"c", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[3], (const void*)"d", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[2]); | ||||
|     lfs2_file_close(&lfs2, &files[3]); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "a") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "b") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "c") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "d") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &files[0], "a", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "b", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[2], "c", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[3], "d", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1; | ||||
|         buffer[0] => 'a'; | ||||
|         lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1; | ||||
|         buffer[0] => 'b'; | ||||
|         lfs2_file_read(&lfs2, &files[2], buffer, 1) => 1; | ||||
|         buffer[0] => 'c'; | ||||
|         lfs2_file_read(&lfs2, &files[3], buffer, 1) => 1; | ||||
|         buffer[0] => 'd'; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[2]); | ||||
|     lfs2_file_close(&lfs2, &files[3]); | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Interspersed remove file test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_t files[4]; | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "a") => 0; | ||||
|     lfs2_remove(&lfs2, "b") => 0; | ||||
|     lfs2_remove(&lfs2, "c") => 0; | ||||
|     lfs2_remove(&lfs2, "d") => 0; | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "e") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1; | ||||
|         buffer[0] => 'e'; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Remove inconveniently test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_t files[4]; | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "f") => 0; | ||||
|  | ||||
|     for (int i = 0; i < 5; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[2]); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "e") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "g") => 0; | ||||
|     info.type => LFS2_TYPE_REG; | ||||
|     info.size => 10; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "g", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1; | ||||
|         buffer[0] => 'e'; | ||||
|         lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1; | ||||
|         buffer[0] => 'g'; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										244
									
								
								tests/test_interspersed.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								tests/test_interspersed.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
|  | ||||
| [[case]] # interspersed file test | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| code = ''' | ||||
|     lfs2_file_t files[FILES]; | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_file_open(&lfs2, &files[j], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(info.size == SIZE); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # interspersed remove file test | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         for (int i = 0; i < SIZE; i++) { | ||||
|             lfs2_file_write(&lfs2, &file, &alphas[j], 1) => 1; | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file); | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs2_file_write(&lfs2, &file, (const void*)"~", 1) => 1; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "zzz") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == FILES); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < FILES; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, 1) => 1; | ||||
|         assert(buffer[0] == '~'); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file); | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # remove inconveniently test | ||||
| define.SIZE = [10, 100] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_t files[3]; | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     for (int i = 0; i < SIZE/2; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_remove(&lfs2, "f") => 0; | ||||
|  | ||||
|     for (int i = 0; i < SIZE/2; i++) { | ||||
|         lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1; | ||||
|         lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|     lfs2_file_close(&lfs2, &files[2]); | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "e") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "g") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     assert(info.size == SIZE); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_open(&lfs2, &files[1], "g", LFS2_O_RDONLY) => 0; | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1; | ||||
|         assert(buffer[0] == 'e'); | ||||
|         lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1; | ||||
|         assert(buffer[0] == 'g'); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &files[0]); | ||||
|     lfs2_file_close(&lfs2, &files[1]); | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant interspersed file test | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     lfs2_file_t files[FILES]; | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|  | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_file_open(&lfs2, &files[j], path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < SIZE; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             size = lfs2_file_size(&lfs2, &files[j]); | ||||
|             assert((int)size >= 0); | ||||
|             if ((int)size <= i) { | ||||
|                 lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1; | ||||
|                 lfs2_file_sync(&lfs2, &files[j]) => 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         assert(info.size == SIZE); | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         sprintf(path, "%c", alphas[j]); | ||||
|         lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) { | ||||
|         for (int j = 0; j < FILES; j++) { | ||||
|             lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs2_file_close(&lfs2, &files[j]); | ||||
|     } | ||||
|      | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| @@ -1,333 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Move tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "a") => 0; | ||||
|     lfs2_mkdir(&lfs2, "b") => 0; | ||||
|     lfs2_mkdir(&lfs2, "c") => 0; | ||||
|     lfs2_mkdir(&lfs2, "d") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "a/hi") => 0; | ||||
|     lfs2_mkdir(&lfs2, "a/hi/hola") => 0; | ||||
|     lfs2_mkdir(&lfs2, "a/hi/bonjour") => 0; | ||||
|     lfs2_mkdir(&lfs2, "a/hi/ohayo") => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "a/hello", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     lfs2_file_write(&lfs2, &file, "hola\n", 5) => 5; | ||||
|     lfs2_file_write(&lfs2, &file, "bonjour\n", 8) => 8; | ||||
|     lfs2_file_write(&lfs2, &file, "ohayo\n", 6) => 6; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move file ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "a/hello", "b/hello") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "a") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move file corrupt source ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "b/hello", "c/hello") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/corrupt.py -n 1 | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move file corrupt source and dest ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "c/hello", "d/hello") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/corrupt.py -n 2 | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "d") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move file after corrupt ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "c/hello", "d/hello") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "d") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move dir ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "a/hi", "b/hi") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "a") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move dir corrupt source ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "b/hi", "c/hi") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/corrupt.py -n 1 | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move dir corrupt source and dest ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "c/hi", "d/hi") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/corrupt.py -n 2 | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "d") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move dir after corrupt ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_rename(&lfs2, "c/hi", "d/hi") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "d") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move check ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "a/hi") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b/hi") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c/hi") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "d/hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "bonjour") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hola") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "ohayo") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "a/hello") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b/hello") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c/hello") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "d/hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 5) => 5; | ||||
|     memcmp(buffer, "hola\n", 5) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 8) => 8; | ||||
|     memcmp(buffer, "bonjour\n", 8) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 6) => 6; | ||||
|     memcmp(buffer, "ohayo\n", 6) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Move state stealing ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "b") => 0; | ||||
|     lfs2_remove(&lfs2, "c") => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "a/hi") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "d/hi") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "bonjour") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "hola") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "ohayo") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "a/hello") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "b") => LFS2_ERR_NOENT; | ||||
|     lfs2_dir_open(&lfs2, &dir, "c") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "d/hello", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 5) => 5; | ||||
|     memcmp(buffer, "hola\n", 5) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 8) => 8; | ||||
|     memcmp(buffer, "bonjour\n", 8) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, 6) => 6; | ||||
|     memcmp(buffer, "ohayo\n", 6) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										1815
									
								
								tests/test_move.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1815
									
								
								tests/test_move.toml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,46 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Orphan tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Orphan test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent") => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent/orphan") => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent/child") => 0; | ||||
|     lfs2_remove(&lfs2, "parent/orphan") => 0; | ||||
| TEST | ||||
| # corrupt most recent commit, this should be the update to the previous | ||||
| # linked-list entry and should orphan the child | ||||
| scripts/corrupt.py | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_ssize_t before = lfs2_fs_size(&lfs2); | ||||
|     before => 8; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_ssize_t orphaned = lfs2_fs_size(&lfs2); | ||||
|     orphaned => 8; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "parent/otherchild") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_ssize_t deorphaned = lfs2_fs_size(&lfs2); | ||||
|     deorphaned => 8; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										120
									
								
								tests/test_orphans.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								tests/test_orphans.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| [[case]] # orphan test | ||||
| in = "lfs2.c" | ||||
| if = 'LFS2_PROG_SIZE <= 0x3fe' # only works with one crc per commit | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent") => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent/orphan") => 0; | ||||
|     lfs2_mkdir(&lfs2, "parent/child") => 0; | ||||
|     lfs2_remove(&lfs2, "parent/orphan") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // corrupt the child's most recent commit, this should be the update | ||||
|     // to the linked-list entry, which should orphan the orphan. Note this | ||||
|     // makes a lot of assumptions about the remove operation. | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "parent/child") => 0; | ||||
|     lfs2_block_t block = dir.m.pair[0]; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     uint8_t bbuffer[LFS2_BLOCK_SIZE]; | ||||
|     cfg.read(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     int off = LFS2_BLOCK_SIZE-1; | ||||
|     while (off >= 0 && bbuffer[off] == LFS2_ERASE_VALUE) { | ||||
|         off -= 1; | ||||
|     } | ||||
|     memset(&bbuffer[off-3], LFS2_BLOCK_SIZE, 3); | ||||
|     cfg.erase(&cfg, block) => 0; | ||||
|     cfg.prog(&cfg, block, 0, bbuffer, LFS2_BLOCK_SIZE) => 0; | ||||
|     cfg.sync(&cfg) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     // this mkdir should both create a dir and deorphan, so size | ||||
|     // should be unchanged | ||||
|     lfs2_mkdir(&lfs2, "parent/otherchild") => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/otherchild", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "parent/child", &info) => 0; | ||||
|     lfs2_stat(&lfs2, "parent/otherchild", &info) => 0; | ||||
|     lfs2_fs_size(&lfs2) => 8; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for orphans, basically just spam mkdir/remove | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
|     const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     for (int i = 0; i < CYCLES; i++) { | ||||
|         // create random path | ||||
|         char full_path[256]; | ||||
|         for (int d = 0; d < DEPTH; d++) { | ||||
|             sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             // is valid dir? | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // try to delete path in reverse order, ignore if dir is not empty | ||||
|             for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs2_remove(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|             } | ||||
|  | ||||
|             lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -1,202 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Path tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "soda") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "soda/hotsoda") => 0; | ||||
|     lfs2_mkdir(&lfs2, "soda/warmsoda") => 0; | ||||
|     lfs2_mkdir(&lfs2, "soda/coldsoda") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Root path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/milk1") => 0; | ||||
|     lfs2_stat(&lfs2, "/milk1", &info) => 0; | ||||
|     strcmp(info.name, "milk1") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Redundant slash path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "//tea//hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "///tea///hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "///milk2") => 0; | ||||
|     lfs2_stat(&lfs2, "///milk2", &info) => 0; | ||||
|     strcmp(info.name, "milk2") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Dot path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "./tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "/./tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "/././tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "/./tea/./hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/./milk3") => 0; | ||||
|     lfs2_stat(&lfs2, "/./milk3", &info) => 0; | ||||
|     strcmp(info.name, "milk3") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Dot dot path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/coldtea/../hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/coldcoffee/../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../soda/../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "coffee/../milk4") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../milk4", &info) => 0; | ||||
|     strcmp(info.name, "milk4") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Trailing dot path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/.", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/./.", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/..", &info) => 0; | ||||
|     strcmp(info.name, "tea") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/hottea/../.", &info) => 0; | ||||
|     strcmp(info.name, "tea") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Root dot dot path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "coffee/../../../../../../milk5") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../milk5", &info) => 0; | ||||
|     strcmp(info.name, "milk5") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Root tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/", &info) => 0; | ||||
|     info.type => LFS2_TYPE_DIR; | ||||
|     strcmp(info.name, "/") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "/", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|         => LFS2_ERR_ISDIR; | ||||
|  | ||||
|     // more corner cases | ||||
|     lfs2_remove(&lfs2, "") => LFS2_ERR_INVAL; | ||||
|     lfs2_remove(&lfs2, ".") => LFS2_ERR_INVAL; | ||||
|     lfs2_remove(&lfs2, "..") => LFS2_ERR_INVAL; | ||||
|     lfs2_remove(&lfs2, "/") => LFS2_ERR_INVAL; | ||||
|     lfs2_remove(&lfs2, "//") => LFS2_ERR_INVAL; | ||||
|     lfs2_remove(&lfs2, "./") => LFS2_ERR_INVAL; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Sketchy path tests ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground") => LFS2_ERR_NOENT; | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Superblock conflict test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "littlefs") => 0; | ||||
|     lfs2_remove(&lfs2, "littlefs") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Max path test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'w', LFS2_NAME_MAX+1); | ||||
|     path[LFS2_NAME_MAX+2] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_NAMETOOLONG; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX+1); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX+2] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Really big path test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     memset(path, 'w', LFS2_NAME_MAX); | ||||
|     path[LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										293
									
								
								tests/test_paths.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								tests/test_paths.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,293 @@ | ||||
|  | ||||
| [[case]] # simple path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/milk") => 0; | ||||
|     lfs2_stat(&lfs2, "/milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # redundant slashes | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "/tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "//tea//hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "///tea///hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "////milk") => 0; | ||||
|     lfs2_stat(&lfs2, "////milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # dot path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "./tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "/./tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "/././tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "/./tea/./hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/./milk") => 0; | ||||
|     lfs2_stat(&lfs2, "/./milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # dot dot path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "coffee/../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "tea/coldtea/../hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "coffee/coldcoffee/../../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "coffee/../coffee/../tea/hottea", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "coffee/../milk") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # trailing dot path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "tea/hottea/", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "tea/hottea/.", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "tea/hottea/./.", &info) => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|     lfs2_stat(&lfs2, "tea/hottea/..", &info) => 0; | ||||
|     assert(strcmp(info.name, "tea") == 0); | ||||
|     lfs2_stat(&lfs2, "tea/hottea/../.", &info) => 0; | ||||
|     assert(strcmp(info.name, "tea") == 0); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # leading dot path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, ".milk") => 0; | ||||
|     lfs2_stat(&lfs2, ".milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     lfs2_stat(&lfs2, "tea/.././.milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root dot dot path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/hottea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/warmtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "tea/coldtea") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "coffee/../../../../../../milk") => 0; | ||||
|     lfs2_stat(&lfs2, "coffee/../../../../../../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs2_stat(&lfs2, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid path tests | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg); | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dirt", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "dirt/ground", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_stat(&lfs2, "dirt/ground/earth", &info) => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "dirt") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "dirt/ground") => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground") => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "dirt/ground", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NOENT; | ||||
|     lfs2_mkdir(&lfs2, "dirt/ground/earth") => LFS2_ERR_NOENT; | ||||
|     lfs2_file_open(&lfs2, &file, "dirt/ground/earth", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root operations | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "/") => LFS2_ERR_EXIST; | ||||
|     lfs2_file_open(&lfs2, &file, "/", LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_ISDIR; | ||||
|  | ||||
|     lfs2_remove(&lfs2, "/") => LFS2_ERR_INVAL; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # root representations | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "/", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, ".", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "..", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "//", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_stat(&lfs2, "./", &info) => 0; | ||||
|     assert(strcmp(info.name, "/") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # superblock conflict test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_remove(&lfs2, "littlefs") => LFS2_ERR_NOENT; | ||||
|  | ||||
|     lfs2_mkdir(&lfs2, "littlefs") => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => 0; | ||||
|     assert(strcmp(info.name, "littlefs") == 0); | ||||
|     assert(info.type == LFS2_TYPE_DIR); | ||||
|     lfs2_remove(&lfs2, "littlefs") => 0; | ||||
|     lfs2_stat(&lfs2, "littlefs", &info) => LFS2_ERR_NOENT; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # max path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     memset(path, 'w', LFS2_NAME_MAX+1); | ||||
|     path[LFS2_NAME_MAX+1] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NAMETOOLONG; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX+1); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX+1] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT) | ||||
|             => LFS2_ERR_NAMETOOLONG; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # really big path test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/hotcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/warmcoffee") => 0; | ||||
|     lfs2_mkdir(&lfs2, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     memset(path, 'w', LFS2_NAME_MAX); | ||||
|     path[LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|  | ||||
|     memcpy(path, "coffee/", strlen("coffee/")); | ||||
|     memset(path+strlen("coffee/"), 'w', LFS2_NAME_MAX); | ||||
|     path[strlen("coffee/")+LFS2_NAME_MAX] = '\0'; | ||||
|     lfs2_mkdir(&lfs2, path) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, path, | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_remove(&lfs2, path) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -1,139 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| ITERATIONS=20 | ||||
| COUNT=10 | ||||
|  | ||||
| echo "=== Relocation tests ===" | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // fill up filesystem so only ~16 blocks are left | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     memset(buffer, 0, 512); | ||||
|     while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, 512) => 512; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // make a child dir to use in bounded space | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Dangling split dir test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < $ITERATIONS; j++) { | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         if (j == $ITERATIONS-1) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     for (int i = 0; i < $COUNT; i++) { | ||||
|         sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     for (int i = 0; i < $COUNT; i++) { | ||||
|         sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Outdated head test ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < $ITERATIONS; j++) { | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 0; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         for (int i = 0; i < $COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										305
									
								
								tests/test_relocations.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								tests/test_relocations.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | ||||
| # specific corner cases worth explicitly testing for | ||||
| [[case]] # dangling split dir test | ||||
| define.ITERATIONS = 20 | ||||
| define.COUNT = 10 | ||||
| define.LFS2_BLOCK_CYCLES = [8, 1] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // fill up filesystem so only ~16 blocks are left | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     memset(buffer, 0, 512); | ||||
|     while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, 512) => 512; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // make a child dir to use in bounded space | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < ITERATIONS; j++) { | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         if (j == ITERATIONS-1) { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs2_remove(&lfs2, path) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # outdated head test | ||||
| define.ITERATIONS = 20 | ||||
| define.COUNT = 10 | ||||
| define.LFS2_BLOCK_CYCLES = [8, 1] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     // fill up filesystem so only ~16 blocks are left | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|     memset(buffer, 0, 512); | ||||
|     while (LFS2_BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, 512) => 512; | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     // make a child dir to use in bounded space | ||||
|     lfs2_mkdir(&lfs2, "child") => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int j = 0; j < ITERATIONS; j++) { | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "child") => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 0; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0; | ||||
|             lfs2_file_write(&lfs2, &file, "hi", 2) => 2; | ||||
|             lfs2_file_close(&lfs2, &file) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|  | ||||
|         lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             info.size => 2; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs2_remove(&lfs2, path) => 0; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for relocations, this is the same as the | ||||
|          # orphan testing, except here we also set block_cycles so that | ||||
|          # almost every tree operation needs a relocation | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
|     const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     for (int i = 0; i < CYCLES; i++) { | ||||
|         // create random path | ||||
|         char full_path[256]; | ||||
|         for (int d = 0; d < DEPTH; d++) { | ||||
|             sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             // is valid dir? | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // try to delete path in reverse order, ignore if dir is not empty | ||||
|             for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs2_remove(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|             } | ||||
|  | ||||
|             lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for relocations, but now with random renames! | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS2_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
|     {FILES=3,  DEPTH=3, CYCLES=20, LFS2_BLOCK_CYCLES=1}, | ||||
| ] | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     srand(1); | ||||
|     const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     for (int i = 0; i < CYCLES; i++) { | ||||
|         // create random path | ||||
|         char full_path[256]; | ||||
|         for (int d = 0; d < DEPTH; d++) { | ||||
|             sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); | ||||
|         } | ||||
|  | ||||
|         // if it does not exist, we create it, else we destroy | ||||
|         int res = lfs2_stat(&lfs2, full_path, &info); | ||||
|         assert(!res || res == LFS2_ERR_NOENT); | ||||
|         if (res == LFS2_ERR_NOENT) { | ||||
|             // create each directory in turn, ignore if dir already exists | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 err = lfs2_mkdir(&lfs2, path); | ||||
|                 assert(!err || err == LFS2_ERR_EXIST); | ||||
|             } | ||||
|  | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 strcpy(path, full_path); | ||||
|                 path[2*d+2] = '\0'; | ||||
|                 lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                 assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                 assert(info.type == LFS2_TYPE_DIR); | ||||
|             } | ||||
|         } else { | ||||
|             assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); | ||||
|             assert(info.type == LFS2_TYPE_DIR); | ||||
|  | ||||
|             // create new random path | ||||
|             char new_path[256]; | ||||
|             for (int d = 0; d < DEPTH; d++) { | ||||
|                 sprintf(&new_path[2*d], "/%c", alpha[rand() % FILES]); | ||||
|             } | ||||
|  | ||||
|             // if new path does not exist, rename, otherwise destroy | ||||
|             res = lfs2_stat(&lfs2, new_path, &info); | ||||
|             assert(!res || res == LFS2_ERR_NOENT); | ||||
|             if (res == LFS2_ERR_NOENT) { | ||||
|                 // stop once some dir is renamed | ||||
|                 for (int d = 0; d < DEPTH; d++) { | ||||
|                     strcpy(&path[2*d], &full_path[2*d]); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     strcpy(&path[128+2*d], &new_path[2*d]); | ||||
|                     path[128+2*d+2] = '\0'; | ||||
|                     err = lfs2_rename(&lfs2, path, path+128); | ||||
|                     assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|                     if (!err) { | ||||
|                         strcpy(path, path+128); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 for (int d = 0; d < DEPTH; d++) { | ||||
|                     strcpy(path, new_path); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     lfs2_stat(&lfs2, path, &info) => 0; | ||||
|                     assert(strcmp(info.name, &path[2*d+1]) == 0); | ||||
|                     assert(info.type == LFS2_TYPE_DIR); | ||||
|                 } | ||||
|                  | ||||
|                 lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|             } else { | ||||
|                 // try to delete path in reverse order, | ||||
|                 // ignore if dir is not empty | ||||
|                 for (int d = DEPTH-1; d >= 0; d--) { | ||||
|                     strcpy(path, full_path); | ||||
|                     path[2*d+2] = '\0'; | ||||
|                     err = lfs2_remove(&lfs2, path); | ||||
|                     assert(!err || err == LFS2_ERR_NOTEMPTY); | ||||
|                 } | ||||
|  | ||||
|                 lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| @@ -1,505 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Seek tests ===" | ||||
|  | ||||
| SMALLSIZE=4 | ||||
| MEDIUMSIZE=128 | ||||
| LARGESIZE=132 | ||||
|  | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_mkdir(&lfs2, "hello") => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf(path, "hello/kitty%03d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|  | ||||
|         lfs2_size_t size = strlen("kittycatcat"); | ||||
|         memcpy(buffer, "kittycatcat", size); | ||||
|         for (int j = 0; j < $LARGESIZE; j++) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple dir seek ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     int i; | ||||
|     for (i = 0; i < $SMALLSIZE; i++) { | ||||
|         sprintf(path, "kitty%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         pos = lfs2_dir_tell(&lfs2, &dir); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|     sprintf(path, "kitty%03d", i); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|     sprintf(path, "kitty%03d", 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|     sprintf(path, "kitty%03d", i); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Large dir seek ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_dir_open(&lfs2, &dir, "hello") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     int i; | ||||
|     for (i = 0; i < $MEDIUMSIZE; i++) { | ||||
|         sprintf(path, "kitty%03d", i); | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         pos = lfs2_dir_tell(&lfs2, &dir); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|     sprintf(path, "kitty%03d", i); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_rewind(&lfs2, &dir) => 0; | ||||
|     sprintf(path, "kitty%03d", 0); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, "..") => 0; | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_seek(&lfs2, &dir, pos) => 0; | ||||
|     sprintf(path, "kitty%03d", i); | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|     strcmp(info.name, path) => 0; | ||||
|  | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple file seek ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     lfs2_size_t size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < $SMALLSIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Large file seek ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     lfs2_size_t size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple file seek and write ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     lfs2_size_t size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < $SMALLSIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     memcpy(buffer, "doggodogdog", size); | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Large file seek and write ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos; | ||||
|     lfs2_size_t size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         if (i != $SMALLSIZE) { | ||||
|             memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         } | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     pos >= 0 => 1; | ||||
|  | ||||
|     memcpy(buffer, "doggodogdog", size); | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Boundary seek and write ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs2_size_t size = strlen("hedgehoghog"); | ||||
|     const lfs2_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { | ||||
|         lfs2_soff_t off = offsets[i]; | ||||
|         memcpy(buffer, "hedgehoghog", size); | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|  | ||||
|         lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Out-of-bounds seek ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/kitty042", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs2_size_t size = strlen("kittycatcat"); | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE*size; | ||||
|     lfs2_file_seek(&lfs2, &file, ($LARGESIZE+$SMALLSIZE)*size, | ||||
|             LFS2_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     memcpy(buffer, "porcupineee", size); | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, ($LARGESIZE+$SMALLSIZE)*size, | ||||
|             LFS2_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "porcupineee", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, $LARGESIZE*size, | ||||
|             LFS2_SEEK_SET) => $LARGESIZE*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -(($LARGESIZE+$SMALLSIZE)*size), | ||||
|             LFS2_SEEK_CUR) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => ($LARGESIZE+1)*size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -(($LARGESIZE+2*$SMALLSIZE)*size), | ||||
|             LFS2_SEEK_END) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => ($LARGESIZE+1)*size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Inline write and seek ---" | ||||
| for SIZE in $SMALLSIZE $MEDIUMSIZE $LARGESIZE | ||||
| do | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "hello/tinykitty$SIZE", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT) => 0; | ||||
|     int j = 0; | ||||
|     int k = 0; | ||||
|  | ||||
|     memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); | ||||
|     for (unsigned i = 0; i < $SIZE; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => i+1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|     for (unsigned i = 0; i < $SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => $SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     for (unsigned i = 0; i < $SIZE; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|         if (i < $SIZE-2) { | ||||
|             uint8_t c[3]; | ||||
|             lfs2_file_seek(&lfs2, &file, -1, LFS2_SEEK_CUR) => i; | ||||
|             lfs2_file_read(&lfs2, &file, &c, 3) => 3; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+3; | ||||
|             lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|             lfs2_file_seek(&lfs2, &file, i+1, LFS2_SEEK_SET) => i+1; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|             lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|     for (unsigned i = 0; i < $SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => $SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => $SIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| done | ||||
|  | ||||
| echo "--- Root seek test ---" | ||||
| ./scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 3; i < $MEDIUMSIZE; i++) { | ||||
|         sprintf(path, "hi%03d", i); | ||||
|         lfs2_mkdir(&lfs2, path) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { | ||||
|         if (i == 0) { | ||||
|             sprintf(path, "."); | ||||
|         } else if (i == 1) { | ||||
|             sprintf(path, ".."); | ||||
|         } else if (i == 2) { | ||||
|             sprintf(path, "hello"); | ||||
|         } else { | ||||
|             sprintf(path, "hi%03d", i); | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|         strcmp(path, info.name) => 0; | ||||
|     } | ||||
|     lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|     lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|     for (int j = 0; j < $MEDIUMSIZE; j++) { | ||||
|         lfs2_soff_t off = -1; | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|         for (int i = 0; i < $MEDIUMSIZE; i++) { | ||||
|             if (i == 0) { | ||||
|                 sprintf(path, "."); | ||||
|             } else if (i == 1) { | ||||
|                 sprintf(path, ".."); | ||||
|             } else if (i == 2) { | ||||
|                 sprintf(path, "hello"); | ||||
|             } else { | ||||
|                 sprintf(path, "hi%03d", i); | ||||
|             } | ||||
|  | ||||
|             if (i == j) { | ||||
|                 off = lfs2_dir_tell(&lfs2, &dir); | ||||
|                 off >= 0 => true; | ||||
|             } | ||||
|  | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(path, info.name) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|  | ||||
|         lfs2_dir_open(&lfs2, &dir, "/") => 0; | ||||
|         lfs2_dir_seek(&lfs2, &dir, off) => 0; | ||||
|         for (int i = j; i < $MEDIUMSIZE; i++) { | ||||
|             if (i == 0) { | ||||
|                 sprintf(path, "."); | ||||
|             } else if (i == 1) { | ||||
|                 sprintf(path, ".."); | ||||
|             } else if (i == 2) { | ||||
|                 sprintf(path, "hello"); | ||||
|             } else { | ||||
|                 sprintf(path, "hi%03d", i); | ||||
|             } | ||||
|  | ||||
|             lfs2_dir_read(&lfs2, &dir, &info) => 1; | ||||
|             strcmp(path, info.name) => 0; | ||||
|         } | ||||
|         lfs2_dir_read(&lfs2, &dir, &info) => 0; | ||||
|         lfs2_dir_close(&lfs2, &dir) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										380
									
								
								tests/test_seek.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								tests/test_seek.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
|  | ||||
| [[case]] # simple file seek | ||||
| define = [ | ||||
|     {COUNT=132, SKIP=4}, | ||||
|     {COUNT=132, SKIP=128}, | ||||
|     {COUNT=200, SKIP=10}, | ||||
|     {COUNT=200, SKIP=100}, | ||||
|     {COUNT=4,   SKIP=1}, | ||||
|     {COUNT=4,   SKIP=2}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos = -1; | ||||
|     size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < SKIP; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     assert(pos >= 0); | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # simple file seek and write | ||||
| define = [ | ||||
|     {COUNT=132, SKIP=4}, | ||||
|     {COUNT=132, SKIP=128}, | ||||
|     {COUNT=200, SKIP=10}, | ||||
|     {COUNT=200, SKIP=100}, | ||||
|     {COUNT=4,   SKIP=1}, | ||||
|     {COUNT=4,   SKIP=2}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     lfs2_soff_t pos = -1; | ||||
|     size = strlen("kittycatcat"); | ||||
|     for (int i = 0; i < SKIP; i++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|         pos = lfs2_file_tell(&lfs2, &file); | ||||
|     } | ||||
|     assert(pos >= 0); | ||||
|  | ||||
|     memcpy(buffer, "doggodogdog", size); | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_rewind(&lfs2, &file) => 0; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "doggodogdog", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|     size = lfs2_file_size(&lfs2, &file); | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # boundary seek and writes | ||||
| define.COUNT = 132 | ||||
| define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"' | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     size = strlen("hedgehoghog"); | ||||
|     const lfs2_soff_t offsets[] = OFFSETS; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { | ||||
|         lfs2_soff_t off = offsets[i]; | ||||
|         memcpy(buffer, "hedgehoghog", size); | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|  | ||||
|         lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|  | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|  | ||||
|         lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "kittycatcat", size) => 0; | ||||
|  | ||||
|         lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hedgehoghog", size) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # out of bounds seek | ||||
| define = [ | ||||
|     {COUNT=132, SKIP=4}, | ||||
|     {COUNT=132, SKIP=128}, | ||||
|     {COUNT=200, SKIP=10}, | ||||
|     {COUNT=200, SKIP=100}, | ||||
|     {COUNT=4,   SKIP=2}, | ||||
|     {COUNT=4,   SKIP=3}, | ||||
| ] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0; | ||||
|     size = strlen("kittycatcat"); | ||||
|     memcpy(buffer, "kittycatcat", size); | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|  | ||||
|     size = strlen("kittycatcat"); | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size, | ||||
|             LFS2_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     memcpy(buffer, "porcupineee", size); | ||||
|     lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size, | ||||
|             LFS2_SEEK_SET) => (COUNT+SKIP)*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "porcupineee", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, COUNT*size, | ||||
|             LFS2_SEEK_SET) => COUNT*size; | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|     memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -((COUNT+SKIP)*size), | ||||
|             LFS2_SEEK_CUR) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, -((COUNT+2*SKIP)*size), | ||||
|             LFS2_SEEK_END) => LFS2_ERR_INVAL; | ||||
|     lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # inline write and seek | ||||
| define.SIZE = [2, 4, 128, 132] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "tinykitty", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT) => 0; | ||||
|     int j = 0; | ||||
|     int k = 0; | ||||
|  | ||||
|     memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => i+1; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         lfs2_file_sync(&lfs2, &file) => 0; | ||||
|         lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|         lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         if (i < SIZE-2) { | ||||
|             uint8_t c[3]; | ||||
|             lfs2_file_seek(&lfs2, &file, -1, LFS2_SEEK_CUR) => i; | ||||
|             lfs2_file_read(&lfs2, &file, &c, 3) => 3; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+3; | ||||
|             lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|             lfs2_file_seek(&lfs2, &file, i+1, LFS2_SEEK_SET) => i+1; | ||||
|             lfs2_file_tell(&lfs2, &file) => i+1; | ||||
|             lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|     for (unsigned i = 0; i < SIZE; i++) { | ||||
|         uint8_t c; | ||||
|         lfs2_file_read(&lfs2, &file, &c, 1) => 1; | ||||
|         c => buffer[k++ % 26]; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_sync(&lfs2, &file) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => SIZE; | ||||
|     lfs2_file_size(&lfs2, &file) => SIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # file seek and write with power-loss | ||||
| # must be power-of-2 for quadratic probing to be exhaustive | ||||
| define.COUNT = [4, 64, 128] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     err = lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY); | ||||
|     assert(!err || err == LFS2_ERR_NOENT); | ||||
|     if (!err) { | ||||
|         if (lfs2_file_size(&lfs2, &file) != 0) { | ||||
|             lfs2_file_size(&lfs2, &file) => 11*COUNT; | ||||
|             for (int j = 0; j < COUNT; j++) { | ||||
|                 memset(buffer, 0, 11+1); | ||||
|                 lfs2_file_read(&lfs2, &file, buffer, 11) => 11; | ||||
|                 assert(memcmp(buffer, "kittycatcat", 11) == 0 || | ||||
|                        memcmp(buffer, "doggodogdog", 11) == 0); | ||||
|             } | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|     if (lfs2_file_size(&lfs2, &file) == 0) { | ||||
|         for (int j = 0; j < COUNT; j++) { | ||||
|             strcpy((char*)buffer, "kittycatcat"); | ||||
|             size = strlen((char*)buffer); | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "doggodogdog"); | ||||
|     size = strlen((char*)buffer); | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     // seek and write using quadratic probing to touch all | ||||
|     // 11-byte words in the file | ||||
|     lfs2_off_t off = 0; | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         off = (5*off + 1) % COUNT; | ||||
|         lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         assert(memcmp(buffer, "kittycatcat", size) == 0 || | ||||
|                memcmp(buffer, "doggodogdog", size) == 0); | ||||
|         if (memcmp(buffer, "doggodogdog", size) != 0) { | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             strcpy((char*)buffer, "doggodogdog"); | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|             lfs2_file_sync(&lfs2, &file) => 0; | ||||
|             lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size; | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|         } | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => COUNT*size; | ||||
|     for (int j = 0; j < COUNT; j++) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         assert(memcmp(buffer, "doggodogdog", size) == 0); | ||||
|     } | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
							
								
								
									
										127
									
								
								tests/test_superblocks.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								tests/test_superblocks.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| [[case]] # simple formatting test | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # mount/unmount | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant format | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # invalid mount | ||||
| code = ''' | ||||
|     lfs2_mount(&lfs2, &cfg) => LFS2_ERR_CORRUPT; | ||||
| ''' | ||||
|  | ||||
| [[case]] # expanding superblock | ||||
| define.LFS2_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.N = [10, 100, 1000] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         lfs2_remove(&lfs2, "dummy") => 0; | ||||
|     } | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "dummy", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # expanding superblock with power cycle | ||||
| define.LFS2_BLOCK_CYCLES = [32, 33, 1] | ||||
| define.N = [10, 100, 1000] | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|         // remove lingering dummy? | ||||
|         err = lfs2_stat(&lfs2, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0)); | ||||
|         if (!err) { | ||||
|             assert(strcmp(info.name, "dummy") == 0); | ||||
|             assert(info.type == LFS2_TYPE_REG); | ||||
|             lfs2_remove(&lfs2, "dummy") => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|         lfs2_unmount(&lfs2) => 0; | ||||
|     } | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant expanding superblock | ||||
| define.LFS2_BLOCK_CYCLES = [2, 1] | ||||
| define.N = 24 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         // remove lingering dummy? | ||||
|         err = lfs2_stat(&lfs2, "dummy", &info); | ||||
|         assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0)); | ||||
|         if (!err) { | ||||
|             assert(strcmp(info.name, "dummy") == 0); | ||||
|             assert(info.type == LFS2_TYPE_REG); | ||||
|             lfs2_remove(&lfs2, "dummy") => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_open(&lfs2, &file, "dummy", | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0; | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|         lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|         assert(strcmp(info.name, "dummy") == 0); | ||||
|         assert(info.type == LFS2_TYPE_REG); | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     // one last check after power-cycle | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_stat(&lfs2, "dummy", &info) => 0; | ||||
|     assert(strcmp(info.name, "dummy") == 0); | ||||
|     assert(info.type == LFS2_TYPE_REG); | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
| @@ -1,355 +0,0 @@ | ||||
| #!/bin/bash | ||||
| set -eu | ||||
| export TEST_FILE=$0 | ||||
| trap 'export TEST_LINE=$LINENO' DEBUG | ||||
|  | ||||
| echo "=== Truncate tests ===" | ||||
|  | ||||
| SMALLSIZE=32 | ||||
| MEDIUMSIZE=2048 | ||||
| LARGESIZE=8192 | ||||
|  | ||||
| rm -rf blocks | ||||
| scripts/test.py << TEST | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple truncate ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     lfs2_size_t size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < $LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, $MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_size_t size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < $MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Truncate and read ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     lfs2_size_t size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < $LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, $MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_size_t size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < $MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_size_t size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < $MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Write, truncate, and read ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "sequence", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|     lfs2_size_t size = lfs2.cfg->cache_size; | ||||
|     lfs2_size_t qsize = size / 4; | ||||
|     uint8_t *wb = buffer; | ||||
|     uint8_t *rb = buffer + size; | ||||
|     for (lfs2_off_t j = 0; j < size; ++j) { | ||||
|         wb[j] = j; | ||||
|     } | ||||
|  | ||||
|     /* Spread sequence over size */ | ||||
|     lfs2_file_write(&lfs2, &file, wb, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_tell(&lfs2, &file) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|  | ||||
|     /* Chop off the last quarter */ | ||||
|     lfs2_size_t trunc = size - qsize; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|  | ||||
|     /* Read should produce first 3/4 */ | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc; | ||||
|     memcmp(rb, wb, trunc) => 0; | ||||
|  | ||||
|     /* Move to 1/4 */ | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|     lfs2_file_seek(&lfs2, &file, qsize, LFS2_SEEK_SET) => qsize; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|  | ||||
|     /* Chop to 1/2 */ | ||||
|     trunc -= qsize; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|      | ||||
|     /* Read should produce second quarter */ | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc - qsize; | ||||
|     memcmp(rb, wb + qsize, trunc - qsize) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Truncate and write ---" | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     lfs2_size_t size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < $LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, $MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     strcpy((char*)buffer, "bald"); | ||||
|     lfs2_size_t size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < $MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => $MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_size_t size = strlen("bald"); | ||||
|     for (lfs2_off_t j = 0; j < $MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "bald", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
|  | ||||
| # More aggressive general truncation tests | ||||
| truncate_test() { | ||||
| STARTSIZES="$1" | ||||
| STARTSEEKS="$2" | ||||
| HOTSIZES="$3" | ||||
| COLDSIZES="$4" | ||||
| scripts/test.py << TEST | ||||
|     static const lfs2_off_t startsizes[] = {$STARTSIZES}; | ||||
|     static const lfs2_off_t startseeks[] = {$STARTSEEKS}; | ||||
|     static const lfs2_off_t hotsizes[]   = {$HOTSIZES}; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|         strcpy((char*)buffer, "hair"); | ||||
|         lfs2_size_t size = strlen((char*)buffer); | ||||
|         for (lfs2_off_t j = 0; j < startsizes[i]; j += size) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|         lfs2_file_size(&lfs2, &file) => startsizes[i]; | ||||
|  | ||||
|         if (startseeks[i] != startsizes[i]) { | ||||
|             lfs2_file_seek(&lfs2, &file, | ||||
|                     startseeks[i], LFS2_SEEK_SET) => startseeks[i]; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_truncate(&lfs2, &file, hotsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     static const lfs2_off_t startsizes[] = {$STARTSIZES}; | ||||
|     static const lfs2_off_t hotsizes[]   = {$HOTSIZES}; | ||||
|     static const lfs2_off_t coldsizes[]  = {$COLDSIZES}; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDWR) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         lfs2_size_t size = strlen("hair"); | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < hotsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_truncate(&lfs2, &file, coldsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| scripts/test.py << TEST | ||||
|     static const lfs2_off_t startsizes[] = {$STARTSIZES}; | ||||
|     static const lfs2_off_t hotsizes[]   = {$HOTSIZES}; | ||||
|     static const lfs2_off_t coldsizes[]  = {$COLDSIZES}; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         lfs2_size_t size = strlen("hair"); | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; | ||||
|                 j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < coldsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| TEST | ||||
| } | ||||
|  | ||||
| echo "--- Cold shrinking truncate ---" | ||||
| truncate_test \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" | ||||
|  | ||||
| echo "--- Cold expanding truncate ---" | ||||
| truncate_test \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" | ||||
|  | ||||
| echo "--- Warm shrinking truncate ---" | ||||
| truncate_test \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,            0,            0,            0,            0" | ||||
|  | ||||
| echo "--- Warm expanding truncate ---" | ||||
| truncate_test \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" | ||||
|  | ||||
| echo "--- Mid-file shrinking truncate ---" | ||||
| truncate_test \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "  $LARGESIZE,   $LARGESIZE,   $LARGESIZE,   $LARGESIZE,   $LARGESIZE" \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,            0,            0,            0,            0" | ||||
|  | ||||
| echo "--- Mid-file expanding truncate ---" | ||||
| truncate_test \ | ||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "           0,            0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ | ||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" | ||||
|  | ||||
| scripts/results.py | ||||
							
								
								
									
										394
									
								
								tests/test_truncate.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								tests/test_truncate.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,394 @@ | ||||
| [[case]] # simple truncate | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|      | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate and read | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("hair"); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "hair", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # write, truncate, and read | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "sequence", | ||||
|             LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|     size = lfs2_min(lfs2.cfg->cache_size, sizeof(buffer)/2); | ||||
|     lfs2_size_t qsize = size / 4; | ||||
|     uint8_t *wb = buffer; | ||||
|     uint8_t *rb = buffer + size; | ||||
|     for (lfs2_off_t j = 0; j < size; ++j) { | ||||
|         wb[j] = j; | ||||
|     } | ||||
|  | ||||
|     /* Spread sequence over size */ | ||||
|     lfs2_file_write(&lfs2, &file, wb, size) => size; | ||||
|     lfs2_file_size(&lfs2, &file) => size; | ||||
|     lfs2_file_tell(&lfs2, &file) => size; | ||||
|  | ||||
|     lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|  | ||||
|     /* Chop off the last quarter */ | ||||
|     lfs2_size_t trunc = size - qsize; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|  | ||||
|     /* Read should produce first 3/4 */ | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc; | ||||
|     memcmp(rb, wb, trunc) => 0; | ||||
|  | ||||
|     /* Move to 1/4 */ | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|     lfs2_file_seek(&lfs2, &file, qsize, LFS2_SEEK_SET) => qsize; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|  | ||||
|     /* Chop to 1/2 */ | ||||
|     trunc -= qsize; | ||||
|     lfs2_file_truncate(&lfs2, &file, trunc) => 0; | ||||
|     lfs2_file_tell(&lfs2, &file) => qsize; | ||||
|     lfs2_file_size(&lfs2, &file) => trunc; | ||||
|      | ||||
|     /* Read should produce second quarter */ | ||||
|     lfs2_file_read(&lfs2, &file, rb, size) => trunc - qsize; | ||||
|     memcmp(rb, wb + qsize, trunc - qsize) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate and write | ||||
| define.MEDIUMSIZE = [32, 2048] | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT) => 0; | ||||
|  | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|  | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     strcpy((char*)buffer, "bald"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDONLY) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|  | ||||
|     size = strlen("bald"); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|         memcmp(buffer, "bald", size) => 0; | ||||
|     } | ||||
|     lfs2_file_read(&lfs2, &file, buffer, size) => 0; | ||||
|  | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # truncate write under powerloss | ||||
| define.SMALLSIZE = [4, 512] | ||||
| define.MEDIUMSIZE = [32, 1024] | ||||
| define.LARGESIZE = 2048 | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     err = lfs2_mount(&lfs2, &cfg); | ||||
|     if (err) { | ||||
|         lfs2_format(&lfs2, &cfg) => 0; | ||||
|         lfs2_mount(&lfs2, &cfg) => 0; | ||||
|     } | ||||
|     err = lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDONLY); | ||||
|     assert(!err || err == LFS2_ERR_NOENT); | ||||
|     if (!err) { | ||||
|         size = lfs2_file_size(&lfs2, &file); | ||||
|         assert(size == 0 || | ||||
|                 size == LARGESIZE || | ||||
|                 size == MEDIUMSIZE || | ||||
|                 size == SMALLSIZE); | ||||
|         for (lfs2_off_t j = 0; j < size; j += 4) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, 4) => 4; | ||||
|             assert(memcmp(buffer, "hair", 4) == 0 || | ||||
|                    memcmp(buffer, "bald", 4) == 0 || | ||||
|                    memcmp(buffer, "comb", 4) == 0); | ||||
|         } | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", | ||||
|             LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => 0; | ||||
|     strcpy((char*)buffer, "hair"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < LARGESIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => LARGESIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     strcpy((char*)buffer, "bald"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => MEDIUMSIZE; | ||||
|     lfs2_file_truncate(&lfs2, &file, SMALLSIZE) => 0; | ||||
|     lfs2_file_size(&lfs2, &file) => SMALLSIZE; | ||||
|     strcpy((char*)buffer, "comb"); | ||||
|     size = strlen((char*)buffer); | ||||
|     for (lfs2_off_t j = 0; j < SMALLSIZE; j += size) { | ||||
|         lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|     } | ||||
|     lfs2_file_size(&lfs2, &file) => SMALLSIZE; | ||||
|     lfs2_file_close(&lfs2, &file) => 0; | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # more aggressive general truncation tests | ||||
| define.CONFIG = 'range(6)' | ||||
| define.SMALLSIZE = 32 | ||||
| define.MEDIUMSIZE = 2048 | ||||
| define.LARGESIZE = 8192 | ||||
| code = ''' | ||||
|     #define COUNT 5 | ||||
|     const struct { | ||||
|         lfs2_off_t startsizes[COUNT]; | ||||
|         lfs2_off_t startseeks[COUNT]; | ||||
|         lfs2_off_t hotsizes[COUNT]; | ||||
|         lfs2_off_t coldsizes[COUNT]; | ||||
|     } configs[] = { | ||||
|         // cold shrinking | ||||
|         {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}}, | ||||
|         // cold expanding | ||||
|         {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}}, | ||||
|         // warm shrinking truncate | ||||
|         {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,           0,           0,           0,           0}}, | ||||
|         // warm expanding truncate | ||||
|         {{          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, | ||||
|         // mid-file shrinking truncate | ||||
|         {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {  LARGESIZE,   LARGESIZE,   LARGESIZE,   LARGESIZE,   LARGESIZE}, | ||||
|          {          0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,           0,           0,           0,           0}}, | ||||
|         // mid-file expanding truncate | ||||
|         {{          0,   SMALLSIZE,   MEDIUMSIZE,  LARGESIZE, 2*LARGESIZE}, | ||||
|          {          0,           0,   SMALLSIZE,  MEDIUMSIZE,   LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, | ||||
|          {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, | ||||
|     }; | ||||
|  | ||||
|     const lfs2_off_t *startsizes = configs[CONFIG].startsizes; | ||||
|     const lfs2_off_t *startseeks = configs[CONFIG].startseeks; | ||||
|     const lfs2_off_t *hotsizes   = configs[CONFIG].hotsizes; | ||||
|     const lfs2_off_t *coldsizes  = configs[CONFIG].coldsizes; | ||||
|  | ||||
|     lfs2_format(&lfs2, &cfg) => 0; | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, | ||||
|                 LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0; | ||||
|  | ||||
|         strcpy((char*)buffer, "hair"); | ||||
|         size = strlen((char*)buffer); | ||||
|         for (lfs2_off_t j = 0; j < startsizes[i]; j += size) { | ||||
|             lfs2_file_write(&lfs2, &file, buffer, size) => size; | ||||
|         } | ||||
|         lfs2_file_size(&lfs2, &file) => startsizes[i]; | ||||
|  | ||||
|         if (startseeks[i] != startsizes[i]) { | ||||
|             lfs2_file_seek(&lfs2, &file, | ||||
|                     startseeks[i], LFS2_SEEK_SET) => startseeks[i]; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_truncate(&lfs2, &file, hotsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDWR) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => hotsizes[i]; | ||||
|  | ||||
|         size = strlen("hair"); | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < hotsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_truncate(&lfs2, &file, coldsizes[i]) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
|  | ||||
|     lfs2_mount(&lfs2, &cfg) => 0; | ||||
|  | ||||
|     for (unsigned i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "hairyhead%d", i); | ||||
|         lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0; | ||||
|         lfs2_file_size(&lfs2, &file) => coldsizes[i]; | ||||
|  | ||||
|         size = strlen("hair"); | ||||
|         lfs2_off_t j = 0; | ||||
|         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; | ||||
|                 j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "hair", size) => 0; | ||||
|         } | ||||
|  | ||||
|         for (; j < coldsizes[i]; j += size) { | ||||
|             lfs2_file_read(&lfs2, &file, buffer, size) => size; | ||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; | ||||
|         } | ||||
|  | ||||
|         lfs2_file_close(&lfs2, &file) => 0; | ||||
|     } | ||||
|  | ||||
|     lfs2_unmount(&lfs2) => 0; | ||||
| ''' | ||||
		Reference in New Issue
	
	Block a user