mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Reworked permutation generation in test framework and cleanup
- Reworked how permutations work - Now with global defines as well (apply to all code) - Also supports lists of different permutation sets - Added better cleanup in tests and "make clean"
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @@ -90,3 +90,4 @@ clean: | |||||||
| 	rm -f $(OBJ) | 	rm -f $(OBJ) | ||||||
| 	rm -f $(DEP) | 	rm -f $(DEP) | ||||||
| 	rm -f $(ASM) | 	rm -f $(ASM) | ||||||
|  | 	rm -f tests_/test_*.toml.* | ||||||
|   | |||||||
							
								
								
									
										101
									
								
								scripts/test_.py
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								scripts/test_.py
									
									
									
									
									
								
							| @@ -1,10 +1,8 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
|  |  | ||||||
| # TODO | # This script manages littlefs tests, which are configured with | ||||||
| # -v --verbose | # .toml files stored in the tests directory. | ||||||
| # --color | # | ||||||
| # --gdb |  | ||||||
| # --reentrant |  | ||||||
|  |  | ||||||
| import toml | import toml | ||||||
| import glob | import glob | ||||||
| @@ -17,6 +15,7 @@ import subprocess as sp | |||||||
| import base64 | import base64 | ||||||
| import sys | import sys | ||||||
| import copy | import copy | ||||||
|  | import shutil | ||||||
|  |  | ||||||
| TEST_DIR = 'tests_' | TEST_DIR = 'tests_' | ||||||
|  |  | ||||||
| @@ -118,21 +117,18 @@ class TestCase: | |||||||
|     def build(self, f, **_): |     def build(self, f, **_): | ||||||
|         # prologue |         # prologue | ||||||
|         f.write('void test_case%d(' % self.caseno) |         f.write('void test_case%d(' % self.caseno) | ||||||
|         defines = self.perms[0].defines |  | ||||||
|         first = True |         first = True | ||||||
|         for k, v in sorted(defines.items()): |         for k, v in sorted(self.perms[0].defines.items()): | ||||||
|             if not all(perm.defines[k] == v for perm in self.perms): |             if k not in self.defines: | ||||||
|                 if not first: |                 if not first: | ||||||
|                     f.write(',') |                     f.write(',') | ||||||
|                 else: |                 else: | ||||||
|                     first = False |                     first = False | ||||||
|                 f.write('\n') |                 f.write('\n') | ||||||
|                 f.write(8*' '+'int %s' % k) |                 f.write(8*' '+'__attribute__((unused)) intmax_t %s' % k) | ||||||
|         f.write(') {\n') |         f.write(') {\n') | ||||||
|  |  | ||||||
|         defines = self.perms[0].defines |         for k, v in sorted(self.defines.items()): | ||||||
|         for k, v in sorted(defines.items()): |  | ||||||
|             if all(perm.defines[k] == v for perm in self.perms): |  | ||||||
|             f.write(4*' '+'#define %s %s\n' % (k, v)) |             f.write(4*' '+'#define %s %s\n' % (k, v)) | ||||||
|  |  | ||||||
|         f.write(PROLOGUE) |         f.write(PROLOGUE) | ||||||
| @@ -147,14 +143,16 @@ class TestCase: | |||||||
|         f.write(EPILOGUE) |         f.write(EPILOGUE) | ||||||
|         f.write('\n') |         f.write('\n') | ||||||
|  |  | ||||||
|         defines = self.perms[0].defines |         for k, v in sorted(self.defines.items()): | ||||||
|         for k, v in sorted(defines.items()): |  | ||||||
|             if all(perm.defines[k] == v for perm in self.perms): |  | ||||||
|             f.write(4*' '+'#undef %s\n' % k) |             f.write(4*' '+'#undef %s\n' % k) | ||||||
|  |  | ||||||
|         f.write('}\n') |         f.write('}\n') | ||||||
|  |  | ||||||
|     def test(self, **args): |     def test(self, **args): | ||||||
|  |         # clear disk first | ||||||
|  |         shutil.rmtree('blocks') | ||||||
|  |  | ||||||
|  |         # build command | ||||||
|         cmd = ['./%s.test' % self.suite.path, |         cmd = ['./%s.test' % self.suite.path, | ||||||
|             repr(self.caseno), repr(self.permno)] |             repr(self.caseno), repr(self.permno)] | ||||||
|  |  | ||||||
| @@ -242,26 +240,31 @@ class TestSuite: | |||||||
|  |  | ||||||
|     def permute(self, defines={}, **args): |     def permute(self, defines={}, **args): | ||||||
|         for case in self.cases: |         for case in self.cases: | ||||||
|             # lets find all parameterized definitions, in one of |             # lets find all parameterized definitions, in one of [args.D, | ||||||
|             # - args.D (defines) |             # suite.defines, case.defines, DEFINES]. Note that each of these | ||||||
|             # - suite.defines |             # can be either a dict of defines, or a list of dicts, expressing | ||||||
|             # - case.defines |             # an initial set of permutations. | ||||||
|             # - DEFINES |             pending = [{}] | ||||||
|             initial = {} |             for inits in [defines, self.defines, case.defines, DEFINES]: | ||||||
|             for define in it.chain( |                 if not isinstance(inits, list): | ||||||
|                     defines.items(), |                     inits = [inits] | ||||||
|                     self.defines.items(), |  | ||||||
|                     case.defines.items(), |                 npending = [] | ||||||
|                     DEFINES.items()): |                 for init, pinit in it.product(inits, pending): | ||||||
|                 if define[0] not in initial: |                     ninit = pinit.copy() | ||||||
|  |                     for k, v in init.items(): | ||||||
|  |                         if k not in ninit: | ||||||
|                             try: |                             try: | ||||||
|                         initial[define[0]] = eval(define[1]) |                                 ninit[k] = eval(v) | ||||||
|                             except: |                             except: | ||||||
|                         initial[define[0]] = define[1] |                                 ninit[k] = v | ||||||
|  |                     npending.append(ninit) | ||||||
|  |  | ||||||
|  |                 pending = npending | ||||||
|  |  | ||||||
|             # expand permutations |             # expand permutations | ||||||
|  |             pending = list(reversed(pending)) | ||||||
|             expanded = [] |             expanded = [] | ||||||
|             pending = [initial] |  | ||||||
|             while pending: |             while pending: | ||||||
|                 perm = pending.pop() |                 perm = pending.pop() | ||||||
|                 for k, v in sorted(perm.items()): |                 for k, v in sorted(perm.items()): | ||||||
| @@ -274,11 +277,27 @@ class TestSuite: | |||||||
|                 else: |                 else: | ||||||
|                     expanded.append(perm) |                     expanded.append(perm) | ||||||
|  |  | ||||||
|  |             # generate permutations | ||||||
|             case.perms = [] |             case.perms = [] | ||||||
|             for i, defines in enumerate(expanded): |             for i, perm in enumerate(expanded): | ||||||
|                 case.perms.append(case.permute(defines, permno=i, **args)) |                 case.perms.append(case.permute(perm, permno=i, **args)) | ||||||
|  |  | ||||||
|  |             # also track non-unique defines | ||||||
|  |             case.defines = {} | ||||||
|  |             for k, v in case.perms[0].defines.items(): | ||||||
|  |                 if all(perm.defines[k] == v for perm in case.perms): | ||||||
|  |                     case.defines[k] = v | ||||||
|  |  | ||||||
|  |         # track all perms and non-unique defines | ||||||
|  |         self.perms = [] | ||||||
|  |         for case in self.cases: | ||||||
|  |             self.perms.extend(case.perms) | ||||||
|  |  | ||||||
|  |         self.defines = {} | ||||||
|  |         for k, v in self.perms[0].defines.items(): | ||||||
|  |             if all(perm.defines[k] == v for perm in self.perms): | ||||||
|  |                 self.defines[k] = v | ||||||
|  |  | ||||||
|         self.perms = [perm for case in self.cases for perm in case.perms] |  | ||||||
|         return self.perms |         return self.perms | ||||||
|  |  | ||||||
|     def build(self, **args): |     def build(self, **args): | ||||||
| @@ -301,7 +320,7 @@ class TestSuite: | |||||||
|             f.write('test_case%d(' % perm.caseno) |             f.write('test_case%d(' % perm.caseno) | ||||||
|             first = True |             first = True | ||||||
|             for k, v in sorted(perm.defines.items()): |             for k, v in sorted(perm.defines.items()): | ||||||
|                 if not all(perm.defines[k] == v for perm in perm.case.perms): |                 if k not in perm.case.defines: | ||||||
|                     if not first: |                     if not first: | ||||||
|                         f.write(', ') |                         f.write(', ') | ||||||
|                     else: |                     else: | ||||||
| @@ -311,13 +330,18 @@ class TestSuite: | |||||||
|         f.write('}\n') |         f.write('}\n') | ||||||
|  |  | ||||||
|         # add test-related rules |         # add test-related rules | ||||||
|         rules = RULES |         rules = RULES.replace(4*' ', '\t') | ||||||
|         rules = rules.replace('    ', '\t') |  | ||||||
|  |  | ||||||
|         with open(self.path + '.test.mk', 'w') as mk: |         with open(self.path + '.test.mk', 'w') as mk: | ||||||
|             mk.write(rules) |             mk.write(rules) | ||||||
|             mk.write('\n') |             mk.write('\n') | ||||||
|  |  | ||||||
|  |             # add truely global defines globally | ||||||
|  |             for k, v in sorted(self.defines.items()): | ||||||
|  |                 mk.write('%s: override CFLAGS += -D%s=%r\n' % ( | ||||||
|  |                     self.path+'.test', k, v)) | ||||||
|  |  | ||||||
|  |             # write test.c in base64 so make can decide when to rebuild | ||||||
|             mk.write('%s: %s\n' % (self.path+'.test.t.c', self.path)) |             mk.write('%s: %s\n' % (self.path+'.test.t.c', self.path)) | ||||||
|             mk.write('\tbase64 -d <<< ') |             mk.write('\tbase64 -d <<< ') | ||||||
|             mk.write(base64.b64encode( |             mk.write(base64.b64encode( | ||||||
| @@ -484,8 +508,13 @@ if __name__ == "__main__": | |||||||
|         help="Overriding parameter definitions.") |         help="Overriding parameter definitions.") | ||||||
|     parser.add_argument('-v', '--verbose', action='store_true', |     parser.add_argument('-v', '--verbose', action='store_true', | ||||||
|         help="Output everything that is happening.") |         help="Output everything that is happening.") | ||||||
|  |     parser.add_argument('-t', '--trace', action='store_true', | ||||||
|  |         help="Normally trace output is captured for internal usage, this \ | ||||||
|  |             enables forwarding trace output which is usually too verbose to \ | ||||||
|  |             be useful.") | ||||||
|     parser.add_argument('-k', '--keep-going', action='store_true', |     parser.add_argument('-k', '--keep-going', action='store_true', | ||||||
|         help="Run all tests instead of stopping on first error. Useful for CI.") |         help="Run all tests instead of stopping on first error. Useful for CI.") | ||||||
|  | # TODO | ||||||
| #    parser.add_argument('--gdb', action='store_true', | #    parser.add_argument('--gdb', action='store_true', | ||||||
| #        help="Run tests under gdb. Useful for debugging failures.") | #        help="Run tests under gdb. Useful for debugging failures.") | ||||||
|     parser.add_argument('--valgrind', action='store_true', |     parser.add_argument('--valgrind', action='store_true', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user