From 65d2b11cc74bc1cdc85b0d0aa4cdc6d6649534ab Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 11:21:09 +0300 Subject: [PATCH 01/13] docs/read.me --- docs/read.me | 126 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 19 deletions(-) diff --git a/docs/read.me b/docs/read.me index 2b5d32f..b3c5a84 100644 --- a/docs/read.me +++ b/docs/read.me @@ -1,19 +1,107 @@ -TESTLIB - -== What is it? == -Testlib is simple library which helps you to write - * checkers - * validators - * generators - * interactors -for programming competitions problems. -You can find latest release of the library on https://github.com/MikeMirzayanov/testlib/ -Problem development management system Polygon completely supports testlib. - -== How to use? == -Easest way is to read c++ sources in the checkers/, validators/, generators/ and interactors/ folders. -Also some classes and methods in testlib have documentation. - -Thanks for using testlib, -Mike Mirzayanov - +# Testlib + +## Intro + +This project contains a C++ implementation of testlib. It is already being used in many programming contests in Russia, such as the Russian National Olympiad in Informatics and different stages of ICPC. Join! + +The library's C++ code is tested for compatibility with standard C++11 and higher on different versions of `g++`, `clang++`, and Microsoft Visual C++. + +This code has been used many times in Codeforces contests. + +## Samples + +### Checker + +This sample checker expects the same integer in the output and the answer. It ignores all white-spaces. See more examples in the package. + +```c++ +#include "testlib.h" + +int main(int argc, char * argv[]) { + setName("compares two signed integers"); + registerTestlibCmd(argc, argv); + int ja = ans.readInt(); + int pa = ouf.readInt(); + if (ja != pa) + quitf(_wa, "expected %d, found %d", ja, pa); + quitf(_ok, "answer is %d", ja); +} +``` + +### Interactor + +This sample interactor reads pairs of numbers from the input file, sends them to another program, reads +the result, and writes it to an output file (to be verified later). Another option could be to terminate +the interactor with `quitf(_wa, )`. + +```c++ +#include "testlib.h" +#include + +using namespace std; + +int main(int argc, char* argv[]) { + setName("Interactor A+B"); + registerInteraction(argc, argv); + + // reads number of queries from test (input) file + int n = inf.readInt(); + for (int i = 0; i < n; i++) { + // reads query from test (input) file + int a = inf.readInt(); + int b = inf.readInt(); + + // writes query to the solution, endl makes flush + cout << a << " " << b << endl; + + // writes output file to be verified by checker later + tout << ouf.readInt() << endl; + } + + // just message + quitf(_ok, "%d queries processed", n); +} +``` + +### Validator + +This code reads input from the standard input and checks that it contains only one integer between 1 and 100, inclusive. It also validates that the file ends with EOLN and EOF. On Windows, it expects #13#10 as EOLN, and it expects #10 as EOLN on other platforms. It does not ignore white-spaces, so it works very strictly. It will return a non-zero code in the case of illegal input and write a message to the standard output. See more examples in the package. + +```c++ +#include "testlib.h" + +int main(int argc, char* argv[]) { + registerValidation(argc, argv); + inf.readInt(1, 100, "n"); + inf.readEoln(); + inf.readEof(); +} +``` + +### Generator + +This generator outputs a random token to the standard output, containing Latin letters or digits. The length of the token will be between 1 and 1000, inclusive. It will use a uniformly distributed random generator. To generate different values, call it with different command-line parameters. It is typical behavior for a testlib generator to set up randseed by command line. See more examples in the package. + +```c++ +#include "testlib.h" + +int main(int argc, char* argv[]) { + registerGen(argc, argv, 1); + println(rnd.next(1, 10)); /* Random number in the range [1,10]. */ + println(rnd.next("[a-zA-Z0-9]{1,1000}")); /* Random word of length [1,1000]. */ +} +``` + +This generator outputs a random permutation; the size is equal to the first command-line argument. + +```c++ +#include "testlib.h" + +int main(int argc, char* argv[]) { + registerGen(argc, argv, 1); + + int n = opt(1); + println(n); + println(rnd.perm(n, 1)); +} +``` From 5b780b36cb7cca62503ea63505e21201870971bf Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 11:27:48 +0300 Subject: [PATCH 02/13] 10000 -> 10'000 and similar --- generators/igen.cpp | 2 +- generators/iwgen.cpp | 10 +++++----- tests/test-001_run-sval-case-nval/src/case-nval.cpp | 2 +- validators/case-nval.cpp | 2 +- validators/nval.cpp | 4 ++-- validators/undirected-graph-validator.cpp | 2 +- validators/undirected-tree-validator.cpp | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/generators/igen.cpp b/generators/igen.cpp index 38be107..5dee1f8 100644 --- a/generators/igen.cpp +++ b/generators/igen.cpp @@ -13,5 +13,5 @@ using namespace std; int main(int argc, char *argv[]) { registerGen(argc, argv, 1); - println(rnd.next(1, 1000000)); + println(rnd.next(1, 1'000'000)); } diff --git a/generators/iwgen.cpp b/generators/iwgen.cpp index 617b7bb..3d1d023 100644 --- a/generators/iwgen.cpp +++ b/generators/iwgen.cpp @@ -7,16 +7,16 @@ * * If parameter "weight" > 0 then you can think about it as code like this: * - * result = rnd.next(1, 1000000); + * result = rnd.next(1, 1'000'000); * for (int i = 0; i < weight; i++) - * result = max(result, rnd.next(1, 1000000)); + * result = max(result, rnd.next(1, 1'000'000)); * * * If parameter "weight" < 0 then you can think about it as code like this: * - * result = rnd.next(1, 1000000); + * result = rnd.next(1, 1'000'000); * for (int i = 0; i < -weight; i++) - * result = min(result, rnd.next(1, 1000000)); + * result = min(result, rnd.next(1, 1'000'000)); * * * It is typical behaviour of "wnext" methods to use this strategy to @@ -30,5 +30,5 @@ using namespace std; int main(int argc, char *argv[]) { registerGen(argc, argv, 1); - println(rnd.wnext(1, 1000000, opt(1))); + println(rnd.wnext(1, 1'000'000, opt(1))); } diff --git a/tests/test-001_run-sval-case-nval/src/case-nval.cpp b/tests/test-001_run-sval-case-nval/src/case-nval.cpp index 928b49c..d525aff 100644 --- a/tests/test-001_run-sval-case-nval/src/case-nval.cpp +++ b/tests/test-001_run-sval-case-nval/src/case-nval.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { for (int testCase = 1; testCase <= testCaseCount; testCase++) { setTestCase(testCase); - int n = inf.readInt(1, 10000, "n"); + int n = inf.readInt(1, 10'000, "n"); inf.readEoln(); inf.readInts(n, -1000, 1000, "a"); inf.readEoln(); diff --git a/validators/case-nval.cpp b/validators/case-nval.cpp index 928b49c..d525aff 100644 --- a/validators/case-nval.cpp +++ b/validators/case-nval.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { for (int testCase = 1; testCase <= testCaseCount; testCase++) { setTestCase(testCase); - int n = inf.readInt(1, 10000, "n"); + int n = inf.readInt(1, 10'000, "n"); inf.readEoln(); inf.readInts(n, -1000, 1000, "a"); inf.readEoln(); diff --git a/validators/nval.cpp b/validators/nval.cpp index 8a6648d..4d594ef 100644 --- a/validators/nval.cpp +++ b/validators/nval.cpp @@ -11,10 +11,10 @@ using namespace std; int main(int argc, char *argv[]) { registerValidation(argc, argv); - int n = inf.readInt(1, 100000, "n"); + int n = inf.readInt(1, 100'000, "n"); inf.readEoln(); - inf.readLongs(n, -1000000000LL * 1000000LL, 1000000000LL * 1000000LL, "a"); + inf.readLongs(n, -1'000'000'000LL * 1'000'000LL, 1'000'000'000LL * 1'000'000LL, "a"); inf.readEoln(); inf.readEof(); diff --git a/validators/undirected-graph-validator.cpp b/validators/undirected-graph-validator.cpp index 747d7ba..b196304 100644 --- a/validators/undirected-graph-validator.cpp +++ b/validators/undirected-graph-validator.cpp @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) { int n = inf.readInt(1, 1000, "n"); inf.readSpace(); - int m = inf.readInt(0, 100000, "m"); + int m = inf.readInt(0, 100'000, "m"); inf.readEoln(); set> edges; diff --git a/validators/undirected-tree-validator.cpp b/validators/undirected-tree-validator.cpp index bd064f6..256d51b 100644 --- a/validators/undirected-tree-validator.cpp +++ b/validators/undirected-tree-validator.cpp @@ -26,7 +26,7 @@ bool merge(vector &dsu, int a, int b) { int main(int argc, char *argv[]) { registerValidation(argc, argv); - int n = inf.readInt(2, 100000, "n"); + int n = inf.readInt(2, 100'000, "n"); inf.readEoln(); vector dsu(n); From 7b15e65abae7858ff78d6c2e664b83011ec21cff Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 11:31:35 +0300 Subject: [PATCH 03/13] revert 10000->10'000, fix macos-12-gpp, macos-13-gpp --- .github/workflows/ci.yml | 4 ++-- generators/igen.cpp | 2 +- generators/iwgen.cpp | 10 +++++----- tests/test-001_run-sval-case-nval/src/case-nval.cpp | 2 +- validators/case-nval.cpp | 2 +- validators/nval.cpp | 4 ++-- validators/undirected-graph-validator.cpp | 2 +- validators/undirected-tree-validator.cpp | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9425a20..894ddd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -180,7 +180,7 @@ jobs: matrix: os: [macos-12] compiler: [g++] - version: [11, 12, 13] + version: [12, 13, 14] name: Use ${{ matrix.compiler }}-${{ matrix.version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} steps: @@ -209,7 +209,7 @@ jobs: matrix: os: [macos-13] compiler: [g++] - version: [11, 12, 13] + version: [12, 13, 14] name: Use ${{ matrix.compiler }}-${{ matrix.version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} steps: diff --git a/generators/igen.cpp b/generators/igen.cpp index 5dee1f8..38be107 100644 --- a/generators/igen.cpp +++ b/generators/igen.cpp @@ -13,5 +13,5 @@ using namespace std; int main(int argc, char *argv[]) { registerGen(argc, argv, 1); - println(rnd.next(1, 1'000'000)); + println(rnd.next(1, 1000000)); } diff --git a/generators/iwgen.cpp b/generators/iwgen.cpp index 3d1d023..617b7bb 100644 --- a/generators/iwgen.cpp +++ b/generators/iwgen.cpp @@ -7,16 +7,16 @@ * * If parameter "weight" > 0 then you can think about it as code like this: * - * result = rnd.next(1, 1'000'000); + * result = rnd.next(1, 1000000); * for (int i = 0; i < weight; i++) - * result = max(result, rnd.next(1, 1'000'000)); + * result = max(result, rnd.next(1, 1000000)); * * * If parameter "weight" < 0 then you can think about it as code like this: * - * result = rnd.next(1, 1'000'000); + * result = rnd.next(1, 1000000); * for (int i = 0; i < -weight; i++) - * result = min(result, rnd.next(1, 1'000'000)); + * result = min(result, rnd.next(1, 1000000)); * * * It is typical behaviour of "wnext" methods to use this strategy to @@ -30,5 +30,5 @@ using namespace std; int main(int argc, char *argv[]) { registerGen(argc, argv, 1); - println(rnd.wnext(1, 1'000'000, opt(1))); + println(rnd.wnext(1, 1000000, opt(1))); } diff --git a/tests/test-001_run-sval-case-nval/src/case-nval.cpp b/tests/test-001_run-sval-case-nval/src/case-nval.cpp index d525aff..928b49c 100644 --- a/tests/test-001_run-sval-case-nval/src/case-nval.cpp +++ b/tests/test-001_run-sval-case-nval/src/case-nval.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { for (int testCase = 1; testCase <= testCaseCount; testCase++) { setTestCase(testCase); - int n = inf.readInt(1, 10'000, "n"); + int n = inf.readInt(1, 10000, "n"); inf.readEoln(); inf.readInts(n, -1000, 1000, "a"); inf.readEoln(); diff --git a/validators/case-nval.cpp b/validators/case-nval.cpp index d525aff..928b49c 100644 --- a/validators/case-nval.cpp +++ b/validators/case-nval.cpp @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { for (int testCase = 1; testCase <= testCaseCount; testCase++) { setTestCase(testCase); - int n = inf.readInt(1, 10'000, "n"); + int n = inf.readInt(1, 10000, "n"); inf.readEoln(); inf.readInts(n, -1000, 1000, "a"); inf.readEoln(); diff --git a/validators/nval.cpp b/validators/nval.cpp index 4d594ef..8a6648d 100644 --- a/validators/nval.cpp +++ b/validators/nval.cpp @@ -11,10 +11,10 @@ using namespace std; int main(int argc, char *argv[]) { registerValidation(argc, argv); - int n = inf.readInt(1, 100'000, "n"); + int n = inf.readInt(1, 100000, "n"); inf.readEoln(); - inf.readLongs(n, -1'000'000'000LL * 1'000'000LL, 1'000'000'000LL * 1'000'000LL, "a"); + inf.readLongs(n, -1000000000LL * 1000000LL, 1000000000LL * 1000000LL, "a"); inf.readEoln(); inf.readEof(); diff --git a/validators/undirected-graph-validator.cpp b/validators/undirected-graph-validator.cpp index b196304..747d7ba 100644 --- a/validators/undirected-graph-validator.cpp +++ b/validators/undirected-graph-validator.cpp @@ -9,7 +9,7 @@ int main(int argc, char *argv[]) { int n = inf.readInt(1, 1000, "n"); inf.readSpace(); - int m = inf.readInt(0, 100'000, "m"); + int m = inf.readInt(0, 100000, "m"); inf.readEoln(); set> edges; diff --git a/validators/undirected-tree-validator.cpp b/validators/undirected-tree-validator.cpp index 256d51b..bd064f6 100644 --- a/validators/undirected-tree-validator.cpp +++ b/validators/undirected-tree-validator.cpp @@ -26,7 +26,7 @@ bool merge(vector &dsu, int a, int b) { int main(int argc, char *argv[]) { registerValidation(argc, argv); - int n = inf.readInt(2, 100'000, "n"); + int n = inf.readInt(2, 100000, "n"); inf.readEoln(); vector dsu(n); From 5f898aa8c90bd001b65da990a5d0d328736ba3bf Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 13:53:54 +0300 Subject: [PATCH 04/13] Fallback to std::format for c++20, fixed some warns --- testlib.h | 112 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 45 deletions(-) diff --git a/testlib.h b/testlib.h index d188bf1..5fece7b 100644 --- a/testlib.h +++ b/testlib.h @@ -25,7 +25,7 @@ * Copyright (c) 2005-2024 */ -#define VERSION "0.9.43" +#define VERSION "0.9.44-SNAPSHOT" /* * Mike Mirzayanov @@ -63,6 +63,7 @@ */ const char *latestFeatures[] = { + "Fallback to std::format for c++20, fixed some warns", "Added ConstantBoundsLog, VariablesLog to validator testOverviewLogFile", "Use setAppesModeEncoding to change xml encoding from windows-1251 to other", "rnd.any/wany use distance/advance instead of -/+: now they support sets/multisets", @@ -330,6 +331,12 @@ static int __testlib_format_buffer_usage_count = 0; result = std::string(__testlib_format_buffer); \ __testlib_format_buffer_usage_count--; \ +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +std::string testlib_format_(const char *fmt, ...); +std::string testlib_format_(const std::string fmt, ...); + const long long __TESTLIB_LONGLONG_MAX = 9223372036854775807LL; const int __TESTLIB_MAX_TEST_CASE = 1073741823; @@ -430,19 +437,6 @@ inline std::string lowerCase(std::string s) { return s; } -#ifdef __GNUC__ -__attribute__ ((format (printf, 1, 2))) -#endif -std::string format(const char *fmt, ...) { - FMT_TO_RESULT(fmt, fmt, result); - return result; -} - -std::string format(const std::string fmt, ...) { - FMT_TO_RESULT(fmt, fmt.c_str(), result); - return result; -} - #ifdef __GNUC__ __attribute__((const)) #endif @@ -1805,7 +1799,7 @@ class FileInputStreamReader : public InputStreamReader { void setTestCase(int testCase) { if (testCase < 0 || testCase > __TESTLIB_MAX_TEST_CASE) - __testlib_fail(format("testCase expected fit in [1,%d], but %d doesn't", __TESTLIB_MAX_TEST_CASE, testCase)); + __testlib_fail(testlib_format_("testCase expected fit in [1,%d], but %d doesn't", __TESTLIB_MAX_TEST_CASE, testCase)); readChars.push_back(testCase + 256); } @@ -3127,7 +3121,7 @@ NORETURN void InStream::quit(TResult result, const char *msg) { break; default: if (result >= _partially) { - errorName = format("partially correct (%d) ", pctype); + errorName = testlib_format_("partially correct (%d) ", pctype); isPartial = true; quitscrS(LightYellow, errorName); } else @@ -3151,7 +3145,7 @@ NORETURN void InStream::quit(TResult result, const char *msg) { else { if (__testlib_points == std::numeric_limits::infinity()) quit(_fail, "Expected points, but infinity found"); - std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", __testlib_points)); + std::string stringPoints = removeDoubleTrailingZeroes(testlib_format_("%.10f", __testlib_points)); std::fprintf(resultFile, "", outcomes[(int) result].c_str(), stringPoints.c_str()); } @@ -3483,9 +3477,9 @@ std::string InStream::readWord(const pattern &p, const std::string &variableName std::vector InStream::readWords(int size, const pattern &p, const std::string &variablesName, int indexBase) { - __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); } std::vector InStream::readWords(int size, int indexBase) { @@ -3499,9 +3493,9 @@ std::string InStream::readWord(const std::string &ptrn, const std::string &varia std::vector InStream::readWords(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { pattern p(ptrn); - __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readWords, readWord(p, variablesName), std::string, true); } std::string InStream::readToken(const pattern &p, const std::string &variableName) { @@ -3510,9 +3504,9 @@ std::string InStream::readToken(const pattern &p, const std::string &variableNam std::vector InStream::readTokens(int size, const pattern &p, const std::string &variablesName, int indexBase) { - __testlib_readMany(readTokens, readToken(p, variablesName), std::string, true); if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readTokens, readToken(p, variablesName), std::string, true); } std::vector InStream::readTokens(int size, int indexBase) { @@ -3526,9 +3520,9 @@ std::string InStream::readToken(const std::string &ptrn, const std::string &vari std::vector InStream::readTokens(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { pattern p(ptrn); - __testlib_readMany(readTokens, readWord(p, variablesName), std::string, true); if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readTokens, readWord(p, variablesName), std::string, true); } void InStream::readWordTo(std::string &result, const pattern &p, const std::string &variableName) { @@ -3893,9 +3887,9 @@ long long InStream::readLong(long long minv, long long maxv, const std::string & std::vector InStream::readLongs(int size, long long minv, long long maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readLongs, readLong(minv, maxv, variablesName), long long, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readLongs, readLong(minv, maxv, variablesName), long long, true) } std::vector InStream::readLongs(int size, int indexBase) { @@ -3939,9 +3933,9 @@ InStream::readUnsignedLong(unsigned long long minv, unsigned long long maxv, con std::vector InStream::readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readUnsignedLongs, readUnsignedLong(minv, maxv, variablesName), unsigned long long, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readUnsignedLongs, readUnsignedLong(minv, maxv, variablesName), unsigned long long, true) } std::vector InStream::readUnsignedLongs(int size, int indexBase) { @@ -3993,9 +3987,9 @@ int InStream::readInteger(int minv, int maxv, const std::string &variableName) { } std::vector InStream::readInts(int size, int minv, int maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readInts, readInt(minv, maxv, variablesName), int, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readInts, readInt(minv, maxv, variablesName), int, true) } std::vector InStream::readInts(int size, int indexBase) { @@ -4003,9 +3997,9 @@ std::vector InStream::readInts(int size, int indexBase) { } std::vector InStream::readIntegers(int size, int minv, int maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readIntegers, readInt(minv, maxv, variablesName), int, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readIntegers, readInt(minv, maxv, variablesName), int, true) } std::vector InStream::readIntegers(int size, int indexBase) { @@ -4059,9 +4053,9 @@ double InStream::readReal(double minv, double maxv, const std::string &variableN std::vector InStream::readReals(int size, double minv, double maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readReals, readReal(minv, maxv, variablesName), double, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readReals, readReal(minv, maxv, variablesName), double, true) } std::vector InStream::readReals(int size, int indexBase) { @@ -4074,9 +4068,9 @@ double InStream::readDouble(double minv, double maxv, const std::string &variabl std::vector InStream::readDoubles(int size, double minv, double maxv, const std::string &variablesName, int indexBase) { - __testlib_readMany(readDoubles, readDouble(minv, maxv, variablesName), double, true) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readDoubles, readDouble(minv, maxv, variablesName), double, true) } std::vector InStream::readDoubles(int size, int indexBase) { @@ -4126,11 +4120,11 @@ double InStream::readStrictReal(double minv, double maxv, std::vector InStream::readStrictReals(int size, double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variablesName, int indexBase) { + if (strict && !variablesName.empty()) + validator.addVariable(variablesName); __testlib_readMany(readStrictReals, readStrictReal(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), double, true) - if (strict && !variablesName.empty()) - validator.addVariable(variablesName); } double InStream::readStrictDouble(double minv, double maxv, @@ -4144,11 +4138,11 @@ double InStream::readStrictDouble(double minv, double maxv, std::vector InStream::readStrictDoubles(int size, double minv, double maxv, int minAfterPointDigitCount, int maxAfterPointDigitCount, const std::string &variablesName, int indexBase) { + if (strict && !variablesName.empty()) + validator.addVariable(variablesName); __testlib_readMany(readStrictDoubles, readStrictDouble(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), double, true) - if (strict && !variablesName.empty()) - validator.addVariable(variablesName); } bool InStream::eof() { @@ -4322,9 +4316,9 @@ std::string InStream::readString(const pattern &p, const std::string &variableNa std::vector InStream::readStrings(int size, const pattern &p, const std::string &variablesName, int indexBase) { - __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) } std::string InStream::readString(const std::string &ptrn, const std::string &variableName) { @@ -4335,9 +4329,9 @@ std::string InStream::readString(const std::string &ptrn, const std::string &var std::vector InStream::readStrings(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { pattern p(ptrn); - __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readStrings, readString(p, variablesName), std::string, false) } void InStream::readLineTo(std::string &result) { @@ -4366,9 +4360,9 @@ std::string InStream::readLine(const pattern &p, const std::string &variableName std::vector InStream::readLines(int size, const pattern &p, const std::string &variablesName, int indexBase) { - __testlib_readMany(readLines, readString(p, variablesName), std::string, false) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readLines, readString(p, variablesName), std::string, false) } std::string InStream::readLine(const std::string &ptrn, const std::string &variableName) { @@ -4378,9 +4372,9 @@ std::string InStream::readLine(const std::string &ptrn, const std::string &varia std::vector InStream::readLines(int size, const std::string &ptrn, const std::string &variablesName, int indexBase) { pattern p(ptrn); - __testlib_readMany(readLines, readString(p, variablesName), std::string, false) if (strict && !variablesName.empty()) validator.addVariable(variablesName); + __testlib_readMany(readLines, readString(p, variablesName), std::string, false) } #ifdef __GNUC__ @@ -4435,7 +4429,7 @@ double __testlib_preparePoints(double points_) { NORETURN void __testlib_quitp(double points, const char *message) { __testlib_points = __testlib_preparePoints(points); - std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", __testlib_points)); + std::string stringPoints = removeDoubleTrailingZeroes(testlib_format_("%.10f", __testlib_points)); std::string quitMessage; if (NULL == message || 0 == strlen(message)) @@ -4448,7 +4442,7 @@ NORETURN void __testlib_quitp(double points, const char *message) { NORETURN void __testlib_quitp(int points, const char *message) { __testlib_points = __testlib_preparePoints(points); - std::string stringPoints = format("%d", points); + std::string stringPoints = testlib_format_("%d", points); std::string quitMessage; if (NULL == message || 0 == strlen(message)) @@ -4764,7 +4758,7 @@ void registerValidation(int argc, char *argv[]) { if (i + 1 < argc) { long long testCase = stringToLongLong(inf, argv[++i]); if (testCase < 1 || testCase >= __TESTLIB_MAX_TEST_CASE) - quit(_fail, format("Argument testCase should be between 1 and %d, but ", __TESTLIB_MAX_TEST_CASE) + quit(_fail, testlib_format_("Argument testCase should be between 1 and %d, but ", __TESTLIB_MAX_TEST_CASE) + toString(testCase) + " found"); validator.setTestCase(int(testCase)); } else @@ -5182,17 +5176,17 @@ std::vector tokenize(const std::string &s, const std::string &separ NORETURN void __testlib_expectedButFound(TResult result, std::string expected, std::string found, const char *prepend) { std::string message; if (strlen(prepend) != 0) - message = format("%s: expected '%s', but found '%s'", + message = testlib_format_("%s: expected '%s', but found '%s'", compress(prepend).c_str(), compress(expected).c_str(), compress(found).c_str()); else - message = format("expected '%s', but found '%s'", + message = testlib_format_("expected '%s', but found '%s'", compress(expected).c_str(), compress(found).c_str()); quit(result, message); } NORETURN void __testlib_expectedButFound(TResult result, double expected, double found, const char *prepend) { - std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); - std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); + std::string expectedString = removeDoubleTrailingZeroes(testlib_format_("%.12f", expected)); + std::string foundString = removeDoubleTrailingZeroes(testlib_format_("%.12f", found)); __testlib_expectedButFound(result, expectedString, foundString, prepend); } @@ -5223,8 +5217,8 @@ __attribute__ ((format (printf, 4, 5))) #endif NORETURN void expectedButFound(TResult result, double expected, double found, const char *prependFormat, ...) { FMT_TO_RESULT(prependFormat, prependFormat, prepend); - std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); - std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); + std::string expectedString = removeDoubleTrailingZeroes(testlib_format_("%.12f", expected)); + std::string foundString = removeDoubleTrailingZeroes(testlib_format_("%.12f", found)); __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str()); } @@ -6199,7 +6193,7 @@ std::string opt(const std::string &key, const std::string &default_value) { void ensureNoUnusedOpts() { for (const auto &opt: __testlib_opts) { if (!opt.second.used) { - __testlib_fail(format("Opts: unused key '%s'", compress(opt.first).c_str())); + __testlib_fail(testlib_format_("Opts: unused key '%s'", compress(opt.first).c_str())); } } } @@ -6217,4 +6211,32 @@ void TestlibFinalizeGuard::autoEnsureNoUnusedOpts() { TestlibFinalizeGuard testlibFinalizeGuard; #endif + +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +std::string testlib_format_(const char *fmt, ...) { + FMT_TO_RESULT(fmt, fmt, result); + return result; +} + +std::string testlib_format_(const std::string fmt, ...) { + FMT_TO_RESULT(fmt, fmt.c_str(), result); + return result; +} + +#if __cplusplus >= 202002L && __has_include() +# include +#else +std::string format(const char *fmt, ...) { + FMT_TO_RESULT(fmt, fmt, result); + return result; +} + +std::string format(const std::string fmt, ...) { + FMT_TO_RESULT(fmt, fmt.c_str(), result); + return result; +} +#endif + #endif From 4df0ed84bdf02c64dc784ffe8d6858c80efecddc Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 14:22:35 +0300 Subject: [PATCH 05/13] fix macos issue? --- testlib.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/testlib.h b/testlib.h index 5fece7b..cbc1074 100644 --- a/testlib.h +++ b/testlib.h @@ -25,7 +25,7 @@ * Copyright (c) 2005-2024 */ -#define VERSION "0.9.44-SNAPSHOT" +#define VERSION "0.9.44" /* * Mike Mirzayanov @@ -6228,15 +6228,17 @@ std::string testlib_format_(const std::string fmt, ...) { #if __cplusplus >= 202002L && __has_include() # include #else -std::string format(const char *fmt, ...) { - FMT_TO_RESULT(fmt, fmt, result); - return result; -} +# ifndef __cpp_lib_format + std::string format(const char *fmt, ...) { + FMT_TO_RESULT(fmt, fmt, result); + return result; + } -std::string format(const std::string fmt, ...) { - FMT_TO_RESULT(fmt, fmt.c_str(), result); - return result; -} + std::string format(const std::string fmt, ...) { + FMT_TO_RESULT(fmt, fmt.c_str(), result); + return result; + } +#endif #endif #endif From 5c1ee388f49df4117dd47c4e485ba242271b0d1d Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Sun, 22 Sep 2024 23:37:32 +0300 Subject: [PATCH 06/13] fix --- testlib.h | 16 +++------------- tests/scripts/compile | 10 +++++++++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/testlib.h b/testlib.h index cbc1074..b7c7008 100644 --- a/testlib.h +++ b/testlib.h @@ -6225,20 +6225,10 @@ std::string testlib_format_(const std::string fmt, ...) { return result; } -#if __cplusplus >= 202002L && __has_include() +#if (__cplusplus >= 202002L && __has_include()) || __cpp_lib_format # include -#else -# ifndef __cpp_lib_format - std::string format(const char *fmt, ...) { - FMT_TO_RESULT(fmt, fmt, result); - return result; - } - - std::string format(const std::string fmt, ...) { - FMT_TO_RESULT(fmt, fmt.c_str(), result); - return result; - } -#endif #endif +#define format testlib_format_ + #endif diff --git a/tests/scripts/compile b/tests/scripts/compile index 6b31f5f..11357b7 100644 --- a/tests/scripts/compile +++ b/tests/scripts/compile @@ -35,7 +35,15 @@ rm -f "$exe_file" EXTRA_ARGS="" if [[ -z "${TESTLIB_COMPILER_OPTIMIZATION_OPT}" ]]; then - OPTIMIZATION="2" + if [[ "$2" == "--check-only" ]]; then + if [[ "$CPP" == "cl.exe" ]]; then + OPTIMIZATION="d" + else + OPTIMIZATION="0" + fi + else + OPTIMIZATION="2" + fi else OPTIMIZATION="${TESTLIB_COMPILER_OPTIMIZATION_OPT}" fi From 748bcf3c4803aab97e30e5d67c3a3abe6b30e4b7 Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Mon, 23 Sep 2024 00:35:00 +0300 Subject: [PATCH 07/13] - macos-11; + test-008_format --- .github/workflows/ci.yml | 29 ------------------- tests/test-008_format/files/test-format.cpp | 14 +++++++++ .../refs/test-format/r1/exit_code | 1 + .../refs/test-format/r1/stderr | 0 .../refs/test-format/r1/stdout | 4 +++ .../refs/test-format/r2/exit_code | 1 + .../refs/test-format/r2/stderr | 0 .../refs/test-format/r2/stdout | 4 +++ tests/test-008_format/run.sh | 7 +++++ 9 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 tests/test-008_format/files/test-format.cpp create mode 100644 tests/test-008_format/refs/test-format/r1/exit_code create mode 100644 tests/test-008_format/refs/test-format/r1/stderr create mode 100644 tests/test-008_format/refs/test-format/r1/stdout create mode 100644 tests/test-008_format/refs/test-format/r2/exit_code create mode 100644 tests/test-008_format/refs/test-format/r2/stderr create mode 100644 tests/test-008_format/refs/test-format/r2/stdout create mode 100644 tests/test-008_format/run.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 894ddd4..55adc4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,35 +146,6 @@ jobs: cd tests bash ./run.sh ${{ matrix.compiler }} v${{ matrix.version }} 32 - tests-macos11-gpp: - strategy: - matrix: - os: [macos-11] - compiler: [g++] - version: [10, 11, 12] - name: Use ${{ matrix.compiler }}-${{ matrix.version }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Run tests - run: | - cd tests - bash ./run.sh ${{ matrix.compiler }} v${{ matrix.version }} - - tests-macos11-clang: - strategy: - matrix: - os: [macos-11] - compiler: [clang++] - name: Use ${{ matrix.compiler }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Run tests - run: | - cd tests - bash ./run.sh ${{ matrix.compiler }} - tests-macos12-gpp: strategy: matrix: diff --git a/tests/test-008_format/files/test-format.cpp b/tests/test-008_format/files/test-format.cpp new file mode 100644 index 0000000..19da939 --- /dev/null +++ b/tests/test-008_format/files/test-format.cpp @@ -0,0 +1,14 @@ +#include "testlib.h" + +using namespace std; + +int main(int argc, char** argv) { + registerGen(argc, argv, 1); + + println(format("%d", 42)); + println(format("hello, %s!", "hat")); + println(format("%s%d!", "'hat'", 42)); + println(format("%s%d!", "'%s'", 42)); + + ensure(format("%f", 42.5).substr(0, 4) == "42.5"); +} diff --git a/tests/test-008_format/refs/test-format/r1/exit_code b/tests/test-008_format/refs/test-format/r1/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format/r1/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format/r1/stderr b/tests/test-008_format/refs/test-format/r1/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format/r1/stdout b/tests/test-008_format/refs/test-format/r1/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format/r1/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/refs/test-format/r2/exit_code b/tests/test-008_format/refs/test-format/r2/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format/r2/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format/r2/stderr b/tests/test-008_format/refs/test-format/r2/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format/r2/stdout b/tests/test-008_format/refs/test-format/r2/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format/r2/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/run.sh b/tests/test-008_format/run.sh new file mode 100644 index 0000000..e7aaf4f --- /dev/null +++ b/tests/test-008_format/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -eo pipefail + +bash ../scripts/compile files/test-format.cpp +bash ../scripts/test-ref test-format/r1 ./test-format +bash ../scripts/test-ref test-format/r2 "$VALGRIND" ./test-format +rm -f test-format test-format.exe From f736340e046746a5c03fc63889de6873a721c883 Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Mon, 23 Sep 2024 00:37:42 +0300 Subject: [PATCH 08/13] + macos-14 --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55adc4d..c7b2b4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -204,6 +204,35 @@ jobs: cd tests bash ./run.sh ${{ matrix.compiler }} + tests-macos14-gpp: + strategy: + matrix: + os: [macos-14] + compiler: [g++] + version: [12, 13, 14] + name: Use ${{ matrix.compiler }}-${{ matrix.version }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Run tests + run: | + cd tests + bash ./run.sh ${{ matrix.compiler }} v${{ matrix.version }} + + tests-macos14-clang: + strategy: + matrix: + os: [macos-14] + compiler: [clang++] + name: Use ${{ matrix.compiler }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Run tests + run: | + cd tests + bash ./run.sh ${{ matrix.compiler }} + tests-windows-2019: strategy: matrix: From 96fd1b8160e25559a972325289c4d70d99d2ecd0 Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Tue, 24 Sep 2024 19:50:23 +0300 Subject: [PATCH 09/13] format issue --- testlib.h | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/testlib.h b/testlib.h index b7c7008..9c86d76 100644 --- a/testlib.h +++ b/testlib.h @@ -4916,10 +4916,10 @@ static inline void __testlib_ensure(bool cond, const char *msg) { quit(_fail, msg); } -#define ensure(cond) __testlib_ensure(cond, "Condition failed: \"" #cond "\"") +#define ensure(cond) __testlib_ensure((cond), "Condition failed: \"" #cond "\"") #define STRINGIZE_DETAIL(x) #x -#define STRINGIZE(x) STRINGIZE_DETAIL(x) -#define ensure_ext(cond) __testlib_ensure(cond, "Line " STRINGIZE(__LINE__) ": Condition failed: \"" #cond "\"") +#define STRINGIZE(x) STRINGIZE_DETAIL((x)) +#define ensure_ext(cond) __testlib_ensure((cond), "Line " STRINGIZE(__LINE__) ": Condition failed: \"" #cond "\"") #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))) @@ -6209,7 +6209,6 @@ void TestlibFinalizeGuard::autoEnsureNoUnusedOpts() { } TestlibFinalizeGuard testlibFinalizeGuard; - #endif #ifdef __GNUC__ @@ -6226,9 +6225,34 @@ std::string testlib_format_(const std::string fmt, ...) { } #if (__cplusplus >= 202002L && __has_include()) || __cpp_lib_format -# include +template +std::string format(const char* fmt, Args&&... args) { + size_t size = size_t(std::snprintf(nullptr, 0, fmt, args...) + 1); + std::vector buffer(size); + std::snprintf(buffer.data(), size, fmt, args...); + return std::string(buffer.data()); +} + +template +std::string format(const std::string fmt, Args&&... args) { + size_t size = size_t(std::snprintf(nullptr, 0, fmt.c_str(), args...) + 1); + std::vector buffer(size); + std::snprintf(buffer.data(), size, fmt.c_str(), args...); + return std::string(buffer.data()); +} +#else +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) #endif +std::string format(const char *fmt, ...) { + FMT_TO_RESULT(fmt, fmt, result); + return result; +} -#define format testlib_format_ +std::string format(const std::string fmt, ...) { + FMT_TO_RESULT(fmt, fmt.c_str(), result); + return result; +} +#endif #endif From 558dd2ef8f0afafeee595967c817b9181f9ba98f Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Tue, 24 Sep 2024 21:00:34 +0300 Subject: [PATCH 10/13] more tests --- testlib.h | 2 +- .../files/test-format-format1.cpp | 18 ++++++++++++++++++ .../files/test-format-format2.cpp | 18 ++++++++++++++++++ .../refs/test-format-format1/r1/exit_code | 1 + .../refs/test-format-format1/r1/stderr | 0 .../refs/test-format-format1/r1/stdout | 4 ++++ .../refs/test-format-format1/r2/exit_code | 1 + .../refs/test-format-format1/r2/stderr | 0 .../refs/test-format-format1/r2/stdout | 4 ++++ .../refs/test-format-format2/r1/exit_code | 1 + .../refs/test-format-format2/r1/stderr | 0 .../refs/test-format-format2/r1/stdout | 4 ++++ .../refs/test-format-format2/r2/exit_code | 1 + .../refs/test-format-format2/r2/stderr | 0 .../refs/test-format-format2/r2/stdout | 4 ++++ tests/test-008_format/run.sh | 10 ++++++++++ 16 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 tests/test-008_format/files/test-format-format1.cpp create mode 100644 tests/test-008_format/files/test-format-format2.cpp create mode 100644 tests/test-008_format/refs/test-format-format1/r1/exit_code create mode 100644 tests/test-008_format/refs/test-format-format1/r1/stderr create mode 100644 tests/test-008_format/refs/test-format-format1/r1/stdout create mode 100644 tests/test-008_format/refs/test-format-format1/r2/exit_code create mode 100644 tests/test-008_format/refs/test-format-format1/r2/stderr create mode 100644 tests/test-008_format/refs/test-format-format1/r2/stdout create mode 100644 tests/test-008_format/refs/test-format-format2/r1/exit_code create mode 100644 tests/test-008_format/refs/test-format-format2/r1/stderr create mode 100644 tests/test-008_format/refs/test-format-format2/r1/stdout create mode 100644 tests/test-008_format/refs/test-format-format2/r2/exit_code create mode 100644 tests/test-008_format/refs/test-format-format2/r2/stderr create mode 100644 tests/test-008_format/refs/test-format-format2/r2/stdout diff --git a/testlib.h b/testlib.h index 9c86d76..6846724 100644 --- a/testlib.h +++ b/testlib.h @@ -4917,7 +4917,7 @@ static inline void __testlib_ensure(bool cond, const char *msg) { } #define ensure(cond) __testlib_ensure((cond), "Condition failed: \"" #cond "\"") -#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE_DETAIL(x) (#x) #define STRINGIZE(x) STRINGIZE_DETAIL((x)) #define ensure_ext(cond) __testlib_ensure((cond), "Line " STRINGIZE(__LINE__) ": Condition failed: \"" #cond "\"") diff --git a/tests/test-008_format/files/test-format-format1.cpp b/tests/test-008_format/files/test-format-format1.cpp new file mode 100644 index 0000000..5f69d16 --- /dev/null +++ b/tests/test-008_format/files/test-format-format1.cpp @@ -0,0 +1,18 @@ +#if (__cplusplus >= 202002L && __has_include()) +# include +#endif + +#include "testlib.h" + +using namespace std; + +int main(int argc, char** argv) { + registerGen(argc, argv, 1); + + println(format("%d", 42)); + println(format("hello, %s!", "hat")); + println(format("%s%d!", "'hat'", 42)); + println(format("%s%d!", "'%s'", 42)); + + ensure(format("%f", 42.5).substr(0, 4) == "42.5"); +} diff --git a/tests/test-008_format/files/test-format-format2.cpp b/tests/test-008_format/files/test-format-format2.cpp new file mode 100644 index 0000000..f79f39e --- /dev/null +++ b/tests/test-008_format/files/test-format-format2.cpp @@ -0,0 +1,18 @@ +#include "testlib.h" + +#if (__cplusplus >= 202002L && __has_include()) +# include +#endif + +using namespace std; + +int main(int argc, char** argv) { + registerGen(argc, argv, 1); + + println(format("%d", 42)); + println(format("hello, %s!", "hat")); + println(format("%s%d!", "'hat'", 42)); + println(format("%s%d!", "'%s'", 42)); + + ensure(format("%f", 42.5).substr(0, 4) == "42.5"); +} diff --git a/tests/test-008_format/refs/test-format-format1/r1/exit_code b/tests/test-008_format/refs/test-format-format1/r1/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format-format1/r1/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format-format1/r1/stderr b/tests/test-008_format/refs/test-format-format1/r1/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format-format1/r1/stdout b/tests/test-008_format/refs/test-format-format1/r1/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format-format1/r1/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/refs/test-format-format1/r2/exit_code b/tests/test-008_format/refs/test-format-format1/r2/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format-format1/r2/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format-format1/r2/stderr b/tests/test-008_format/refs/test-format-format1/r2/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format-format1/r2/stdout b/tests/test-008_format/refs/test-format-format1/r2/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format-format1/r2/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/refs/test-format-format2/r1/exit_code b/tests/test-008_format/refs/test-format-format2/r1/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format-format2/r1/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format-format2/r1/stderr b/tests/test-008_format/refs/test-format-format2/r1/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format-format2/r1/stdout b/tests/test-008_format/refs/test-format-format2/r1/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format-format2/r1/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/refs/test-format-format2/r2/exit_code b/tests/test-008_format/refs/test-format-format2/r2/exit_code new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/test-008_format/refs/test-format-format2/r2/exit_code @@ -0,0 +1 @@ +0 diff --git a/tests/test-008_format/refs/test-format-format2/r2/stderr b/tests/test-008_format/refs/test-format-format2/r2/stderr new file mode 100644 index 0000000..e69de29 diff --git a/tests/test-008_format/refs/test-format-format2/r2/stdout b/tests/test-008_format/refs/test-format-format2/r2/stdout new file mode 100644 index 0000000..e0f278f --- /dev/null +++ b/tests/test-008_format/refs/test-format-format2/r2/stdout @@ -0,0 +1,4 @@ +42 +hello, hat! +'hat'42! +'%s'42! diff --git a/tests/test-008_format/run.sh b/tests/test-008_format/run.sh index e7aaf4f..a670325 100644 --- a/tests/test-008_format/run.sh +++ b/tests/test-008_format/run.sh @@ -5,3 +5,13 @@ bash ../scripts/compile files/test-format.cpp bash ../scripts/test-ref test-format/r1 ./test-format bash ../scripts/test-ref test-format/r2 "$VALGRIND" ./test-format rm -f test-format test-format.exe + +bash ../scripts/compile files/test-format-format1.cpp +bash ../scripts/test-ref test-format-format1/r1 ./test-format-format1 +bash ../scripts/test-ref test-format-format1/r2 "$VALGRIND" ./test-format-format1 +rm -f test-format-format1 test-format-format1.exe + +bash ../scripts/compile files/test-format-format2.cpp +bash ../scripts/test-ref test-format-format2/r1 ./test-format-format2 +bash ../scripts/test-ref test-format-format2/r2 "$VALGRIND" ./test-format-format2 +rm -f test-format-format2 test-format-format2.exe From 3ec5caf1f3e2d99d433428b3a85a4848cbc68e74 Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Wed, 25 Sep 2024 15:00:22 +0300 Subject: [PATCH 11/13] use sscanf_s and similar for msvc --- testlib.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/testlib.h b/testlib.h index 6846724..535e0a9 100644 --- a/testlib.h +++ b/testlib.h @@ -667,6 +667,30 @@ static std::string toString(const T &t) { void prepareOpts(int argc, char* argv[]); #endif +FILE* testlib_fopen_(const char* path, const char* mode) { +#ifdef _MSC_VER + FILE* result = NULL; + if (fopen_s(&result, path, mode) != 0) + return NULL; + else + return result; +#else + return std::fopen(path, mode); +#endif +} + +FILE* testlib_freopen_(const char* path, const char* mode, FILE* file) { +#ifdef _MSC_VER + FILE* result = NULL; + if (freopen_s(&result, path, mode, file) != 0) + return NULL; + else + return result; +#else + return std::freopen(path, mode, file); +#endif +} + /* * Very simple regex-like pattern. * It used for two purposes: validation and generation. @@ -1417,7 +1441,11 @@ static void __pattern_scanCounts(const std::string &s, size_t &pos, int &from, i if (parts[i].length() == 0) __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); int number; +#ifdef _MSC_VER + if (sscanf_s(parts[i].c_str(), "%d", &number) != 1) +#else if (std::sscanf(parts[i].c_str(), "%d", &number) != 1) +#endif __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); numbers.push_back(number); } @@ -2633,7 +2661,7 @@ class Validator { else if (fileName == "stderr") f = stderr, standard_file = true; else { - f = fopen(fileName.c_str(), "wb"); + f = testlib_fopen_(fileName.c_str(), "wb"); if (NULL == f) __testlib_fail("Validator::writeTestOverviewLog: can't write test overview log to (" + fileName + ")"); } @@ -2676,7 +2704,7 @@ class Validator { else if (_testMarkupFileName == "stderr") f = stderr, standard_file = true; else { - f = fopen(_testMarkupFileName.c_str(), "wb"); + f = testlib_fopen_(_testMarkupFileName.c_str(), "wb"); if (NULL == f) __testlib_fail("Validator::writeTestMarkup: can't write test markup to (" + _testMarkupFileName + ")"); } @@ -2723,7 +2751,7 @@ class Validator { else if (_testCaseFileName == "stderr") f = stderr, standard_file = true; else { - f = fopen(_testCaseFileName.c_str(), "wb"); + f = testlib_fopen_(_testCaseFileName.c_str(), "wb"); if (NULL == f) __testlib_fail("Validator::writeTestCase: can't write test case to (" + _testCaseFileName + ")"); } @@ -3129,7 +3157,7 @@ NORETURN void InStream::quit(TResult result, const char *msg) { } if (resultName != "") { - resultFile = std::fopen(resultName.c_str(), "w"); + resultFile = testlib_fopen_(resultName.c_str(), "w"); if (resultFile == NULL) { resultName = ""; quit(_fail, "Can not write to the result file"); @@ -3246,7 +3274,7 @@ void InStream::reset(std::FILE *file) { close(); if (!stdfile && NULL == file) - if (NULL == (file = std::fopen(name.c_str(), "rb"))) { + if (NULL == (file = testlib_fopen_(name.c_str(), "rb"))) { if (mode == _output) quits(_pe, std::string("Output file not found: \"") + name + "\""); @@ -3651,7 +3679,12 @@ static inline double stringToDouble(InStream &in, const char *buffer) { char *suffix = new char[length + 1]; std::memset(suffix, 0, length + 1); - int scanned = std::sscanf(buffer, "%lf%s", &result, suffix); + int scanned; +#ifdef _MSC_VER + scanned = sscanf_s(buffer, "%lf%s", &result, suffix, length + 1); +#else + scanned = std::sscanf(buffer, "%lf%s", &result, suffix); +#endif bool empty = strlen(suffix) == 0; delete[] suffix; @@ -3728,7 +3761,12 @@ static inline double stringToStrictDouble(InStream &in, const char *buffer, char *suffix = new char[length + 1]; std::memset(suffix, 0, length + 1); - int scanned = std::sscanf(buffer, "%lf%s", &result, suffix); + int scanned; +#ifdef _MSC_VER + scanned = sscanf_s(buffer, "%lf%s", &result, suffix, length + 1); +#else + scanned = std::sscanf(buffer, "%lf%s", &result, suffix); +#endif bool empty = strlen(suffix) == 0; delete[] suffix; @@ -5007,7 +5045,7 @@ void srand(unsigned int seed) RAND_THROW_STATEMENT void startTest(int test) { const std::string testFileName = vtos(test); - if (NULL == freopen(testFileName.c_str(), "wt", stdout)) + if (NULL == testlib_freopen_(testFileName.c_str(), "wt", stdout)) __testlib_fail("Unable to write file '" + testFileName + "'"); } @@ -6000,7 +6038,11 @@ double deserializePoints(std::string s) { return std::numeric_limits::quiet_NaN(); else { double result; - ensuref(sscanf(s.c_str(), "%lf", &result) == 1, "Invalid serialized points"); +#ifdef _MSC_VER + ensuref(sscanf_s(s.c_str(), "%lf", &result) == 1, "Invalid serialized points"); +#else + ensuref(std::sscanf(s.c_str(), "%lf", &result) == 1, "Invalid serialized points"); +#endif return result; } } From 7c3388f9392852d11699d504c5bbab2552b25a49 Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Wed, 25 Sep 2024 15:25:45 +0300 Subject: [PATCH 12/13] some msvc warn fixed --- testlib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testlib.h b/testlib.h index 535e0a9..e19ff09 100644 --- a/testlib.h +++ b/testlib.h @@ -3681,7 +3681,7 @@ static inline double stringToDouble(InStream &in, const char *buffer) { std::memset(suffix, 0, length + 1); int scanned; #ifdef _MSC_VER - scanned = sscanf_s(buffer, "%lf%s", &result, suffix, length + 1); + scanned = sscanf_s(buffer, "%lf%s", &result, suffix, (unsigned int)(length + 1)); #else scanned = std::sscanf(buffer, "%lf%s", &result, suffix); #endif @@ -3763,7 +3763,7 @@ static inline double stringToStrictDouble(InStream &in, const char *buffer, std::memset(suffix, 0, length + 1); int scanned; #ifdef _MSC_VER - scanned = sscanf_s(buffer, "%lf%s", &result, suffix, length + 1); + scanned = sscanf_s(buffer, "%lf%s", &result, suffix, (unsigned int)(length + 1)); #else scanned = std::sscanf(buffer, "%lf%s", &result, suffix); #endif From f5d22658a7f21cfb3194ac8183071b71da4a777d Mon Sep 17 00:00:00 2001 From: mikemirzayanov Date: Wed, 25 Sep 2024 17:56:26 +0300 Subject: [PATCH 13/13] Removed meaningless update comment --- testlib.h | 1 - 1 file changed, 1 deletion(-) diff --git a/testlib.h b/testlib.h index e19ff09..4e1d368 100644 --- a/testlib.h +++ b/testlib.h @@ -63,7 +63,6 @@ */ const char *latestFeatures[] = { - "Fallback to std::format for c++20, fixed some warns", "Added ConstantBoundsLog, VariablesLog to validator testOverviewLogFile", "Use setAppesModeEncoding to change xml encoding from windows-1251 to other", "rnd.any/wany use distance/advance instead of -/+: now they support sets/multisets",