Add unit test for the version parser
This commit is contained in:
		
							parent
							
								
									a9526ae663
								
							
						
					
					
						commit
						7c7ba729f5
					
				
							
								
								
									
										61
									
								
								src/include/version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/include/version.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /* Copyright (c) 2022 Barcelona Supercomputing Center (BSC)
 | ||||
|  * SPDX-License-Identifier: MIT */ | ||||
| 
 | ||||
| #define _GNU_SOURCE | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include "common.h" | ||||
| 
 | ||||
| static inline int | ||||
| version_parse(const char *version, int tuple[3]) | ||||
| { | ||||
| 	char buf[64]; | ||||
| 
 | ||||
| 	if (strlen(version) >= 64) { | ||||
| 		err("parse_version: version too long: %s\n", version); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	strcpy(buf, version); | ||||
| 
 | ||||
| 	char *str = buf; | ||||
| 	char *which[] = { "major", "minor", "patch" }; | ||||
| 	char *delim[] = { ".", ".", ".-" }; | ||||
| 	char *save = NULL; | ||||
| 
 | ||||
| 	for (int i = 0; i < 3; i++) { | ||||
| 		char *num = strtok_r(str, delim[i], &save); | ||||
| 
 | ||||
| 		/* Subsequent calls need NULL as string */ | ||||
| 		str = NULL; | ||||
| 
 | ||||
| 		if (num == NULL) { | ||||
| 			err("parse_version: missing %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		errno = 0; | ||||
| 		char *endptr = NULL; | ||||
| 		int v = (int) strtol(num, &endptr, 10); | ||||
| 
 | ||||
| 		if (errno != 0 || endptr == num || endptr[0] != '\0') { | ||||
| 			err("parse_version: failed to parse %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		if (v < 0) { | ||||
| 			err("parse_version: invalid negative %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		tuple[i] = v; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -17,6 +17,7 @@ | ||||
| #include "compat.h" | ||||
| #include "ovni.h" | ||||
| #include "parson.h" | ||||
| #include "version.h" | ||||
| 
 | ||||
| /* Data per process */ | ||||
| struct ovni_rproc rproc = {0}; | ||||
| @ -24,57 +25,6 @@ struct ovni_rproc rproc = {0}; | ||||
| /* Data per thread */ | ||||
| _Thread_local struct ovni_rthread rthread = {0}; | ||||
| 
 | ||||
| static int | ||||
| parse_version(const char *version, int tuple[3]) | ||||
| { | ||||
| 	char buf[64]; | ||||
| 
 | ||||
| 	if (strlen(version) >= 64) { | ||||
| 		err("parse_version: version too long: %s\n", version); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	strcpy(buf, version); | ||||
| 
 | ||||
| 	char *str = buf; | ||||
| 	char *which[] = { "major", "minor", "patch" }; | ||||
| 	char *delim[] = { ".", ".", ".-" }; | ||||
| 	char *save = NULL; | ||||
| 
 | ||||
| 	for (int i = 0; i < 3; i++) { | ||||
| 		char *num = strtok_r(str, delim[i], &save); | ||||
| 
 | ||||
| 		/* Subsequent calls need NULL as string */ | ||||
| 		str = NULL; | ||||
| 
 | ||||
| 		if (num == NULL) { | ||||
| 			err("parse_version: missing %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		errno = 0; | ||||
| 		char *endptr = NULL; | ||||
| 		int v = (int) strtol(num, &endptr, 10); | ||||
| 
 | ||||
| 		if (errno != 0 || endptr == num || endptr[0] != '\0') { | ||||
| 			err("parse_version: failed to parse %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		if (v < 0) { | ||||
| 			err("parse_version: invalid negative %s number: %s\n", | ||||
| 					which[i], version); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		tuple[i] = v; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ovni_version_check_str(const char *version) | ||||
| { | ||||
| 	if (version == NULL) | ||||
| @ -83,10 +33,10 @@ void ovni_version_check_str(const char *version) | ||||
| 	int provided[3]; | ||||
| 	int expected[3]; | ||||
| 
 | ||||
| 	if (parse_version(version, provided) != 0) | ||||
| 	if (version_parse(version, provided) != 0) | ||||
| 		die("failed to parse provided version \"%s\"\n", version); | ||||
| 
 | ||||
| 	if (parse_version(OVNI_LIB_VERSION, expected) != 0) | ||||
| 	if (version_parse(OVNI_LIB_VERSION, expected) != 0) | ||||
| 		die("failed to parse expected version \"%s\"\n", OVNI_LIB_VERSION); | ||||
| 
 | ||||
| 	/* Match the major */ | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| # Copyright (c) 2022 Barcelona Supercomputing Center (BSC) | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
| 
 | ||||
| # Example: unit_test(abc.c) | ||||
| unit_test(version.c) | ||||
|  | ||||
							
								
								
									
										45
									
								
								test/unit/version.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								test/unit/version.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| #include "version.h" | ||||
| 
 | ||||
| struct testcase { | ||||
| 	int rc; | ||||
| 	char *version; | ||||
| 	int tuple[3]; | ||||
| }; | ||||
| 
 | ||||
| int main(void) | ||||
| { | ||||
| 	struct testcase cases[] = { | ||||
| 		/* Good */ | ||||
| 		{ 0, "0.0.0", 		{ 0, 0, 0 } }, | ||||
| 		{ 0, "1.0.0", 		{ 1, 0, 0 } }, | ||||
| 		{ 0, "0.1.0", 		{ 0, 1, 0 } }, | ||||
| 		{ 0, "0.0.1", 		{ 0, 0, 1 } }, | ||||
| 		{ 0, "1.2.3-rc1", 	{ 1, 2, 3 } }, | ||||
| 		/* Bad */ | ||||
| 		{ -1, "-1.0.0",		{ 0, 0, 0 } }, | ||||
| 		{ -1, "1.2", 		{ 0, 0, 0 } }, | ||||
| 		{ -1, "1",		{ 0, 0, 0 } }, | ||||
| 		{ -1, "1.O.O",		{ 0, 0, 0 } }, | ||||
| 		{ -1, "1.2.3rc",	{ 0, 0, 0 } }, | ||||
| 	}; | ||||
| 
 | ||||
| 	int n = sizeof(cases) / sizeof(cases[0]); | ||||
| 
 | ||||
| 	for (int i = 0; i < n; i++) { | ||||
| 		struct testcase *c = &cases[i]; | ||||
| 		int tuple[3] = { 0 }; | ||||
| 
 | ||||
| 		if (version_parse(c->version, tuple) != c->rc) | ||||
| 			die("wrong return value\n"); | ||||
| 
 | ||||
| 		if (c->rc != 0) | ||||
| 			continue; | ||||
| 
 | ||||
| 		for (int j = 0; j < 3; j++) { | ||||
| 			if (tuple[j] != c->tuple[j]) | ||||
| 				die("wrong parsed version\n"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user