From a7e17da2163da9b835a50aa24948070f87329416 Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Fri, 7 Aug 2020 21:06:05 -0700 Subject: [PATCH 1/4] fix: add checks for minimum and maximum out of bounds and add tests for the number type --- .../tooling/fast-tooling-wasm/package.json | 3 +- .../permutator/__tests__/test.c | 285 +++++++++++++++++- .../permutator/permutate_number.c | 58 ++-- .../fast-tooling-wasm/permutator/type.c | 2 +- 4 files changed, 323 insertions(+), 25 deletions(-) diff --git a/packages/tooling/fast-tooling-wasm/package.json b/packages/tooling/fast-tooling-wasm/package.json index 9c46711936f..a27d39527b2 100644 --- a/packages/tooling/fast-tooling-wasm/package.json +++ b/packages/tooling/fast-tooling-wasm/package.json @@ -19,7 +19,8 @@ "build": "yarn build:permutator", "build:permutator": "node ./permutator/build.js", "test:permutator": "node ./permutator/build.js --test && cd permutator/__tests__/ && ./test", - "start": "webpack-dev-server" + "start": "webpack-dev-server", + "test": "yarn test:permutator" }, "devDependencies": { "copy-webpack-plugin": "^6.0.3", diff --git a/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c b/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c index 33020a43cc4..31d707a3670 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c +++ b/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c @@ -2,27 +2,92 @@ #include "dbg.h" #include "minunit.h" #include +#include +#include +#include "../cjson/cJSON.h" #include "../permutate.h" +#include "../type.h" -typedef int (*lib_function) (const char *data); +typedef struct PermutatedType (*lib_function) (int iteration, struct cJSON *data); char *lib_file = "libpermutate.so"; void *lib = NULL; -int check_function(const char *func_to_run, const char *data, int expected) +int check_number_type_exact_function( + const char *func_to_run, + const int iteration, + cJSON *data, + struct PermutatedType expected +) { lib_function func = dlsym(lib, func_to_run); check(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror()); - int rc = func(data); - check(rc == expected, "Function %s return %d for data: %s", - func_to_run, rc, data); + struct PermutatedType rc = func(iteration, data); + check(rc.t.number == expected.t.number, "Function %s return %d for data supplied", + func_to_run, (int) rc.t.number); return 1; error: return 0; } +int check_number_type_random_function( + const char *func_to_run, + const int iteration, + cJSON *data, + bool (*tester)(double data) +) +{ + lib_function func = dlsym(lib, func_to_run); + check(func != NULL, + "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror()); + + struct PermutatedType rc = func(iteration, data); + check(tester(rc.t.number), "Function %s return %d for data supplied", + func_to_run, (int) rc.t.number); + + return 1; +error: + return 0; +} + +bool testMinimum(double data) +{ + + return data >= 99; +} + +bool testExclusiveMinimum(double data) +{ + return data > 99; +} + +bool testMaximum(double data) +{ + return data <= 1; +} + +bool testExclusiveMaximum(double data) +{ + return data < 1; +} + +bool testMinimumAndMaximum(double data) +{ + return data >= 6 && data <= 7; +} + +bool testExclusiveMinimumAndMaximum(double data) +{ + return data > 6 && data < 8; +} + +bool testMultipleOf(double data) +{ + return fmod(data,10) == 0; +} + char *test_dlopen() { lib = dlopen(lib_file, RTLD_NOW); @@ -31,11 +96,221 @@ char *test_dlopen() return NULL; } +char *test_number_type() +{ + /** + * Default provided + */ + cJSON *defaultConfig = cJSON_Parse("{\"default\": 5}"); + struct PermutatedType defaultConfigExpected = {0}; + defaultConfigExpected.t.number = 5; + + mu_assert( + check_number_type_exact_function( + "permutate_number", + 0, + defaultConfig, + defaultConfigExpected + ), + "Failed: should have supplied a default" + ); + + /** + * Enum provided + */ + cJSON *enumConfig = cJSON_Parse("{\"enum\": [8,4,1]}"); + struct PermutatedType enumConfigExpected0 = {0}; + enumConfigExpected0.t.number = 8; + struct PermutatedType enumConfigExpected1 = {0}; + enumConfigExpected1.t.number = 4; + struct PermutatedType enumConfigExpected2 = {0}; + enumConfigExpected2.t.number = 1; + struct PermutatedType enumConfigExpected3 = {0}; + enumConfigExpected3.t.number = 8; + + mu_assert( + check_number_type_exact_function( + "permutate_number", + 0, + enumConfig, + enumConfigExpected0 + ), + "Failed: should have supplied a value from an enum" + ); + mu_assert( + check_number_type_exact_function( + "permutate_number", + 1, + enumConfig, + enumConfigExpected1 + ), + "Failed: should have supplied a value from an enum" + ); + mu_assert( + check_number_type_exact_function( + "permutate_number", + 2, + enumConfig, + enumConfigExpected2 + ), + "Failed: should have supplied a value from an enum" + ); + mu_assert( + check_number_type_exact_function( + "permutate_number", + 3, + enumConfig, + enumConfigExpected3 + ), + "Failed: should have supplied a value from an enum" + ); + + /** + * Examples provided + */ + cJSON *examplesConfig = cJSON_Parse("{\"examples\": [9,40,13]}"); + struct PermutatedType examplesConfigExpected0 = {0}; + examplesConfigExpected0.t.number = 9; + struct PermutatedType examplesConfigExpected1 = {0}; + examplesConfigExpected1.t.number = 40; + struct PermutatedType examplesConfigExpected2 = {0}; + examplesConfigExpected2.t.number = 13; + + mu_assert( + check_number_type_exact_function( + "permutate_number", + 0, + examplesConfig, + examplesConfigExpected0 + ), + "Failed: should have supplied a value from an enum" + ); + mu_assert( + check_number_type_exact_function( + "permutate_number", + 1, + examplesConfig, + examplesConfigExpected1 + ), + "Failed: should have supplied a value from an enum" + ); + mu_assert( + check_number_type_exact_function( + "permutate_number", + 2, + examplesConfig, + examplesConfigExpected2 + ), + "Failed: should have supplied a value from an enum" + ); + + /** + * Minimum provided + */ + cJSON *minimumConfig = cJSON_Parse("{\"minimum\": 99}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + minimumConfig, + testMinimum + ), + "Failed: should have supplied a random value above a minimum" + ); + + /** + * Maximum provided + */ + cJSON *maximumConfig = cJSON_Parse("{\"maximum\": 1}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + maximumConfig, + testMaximum + ), + "Failed: should have supplied a random value below a maximum" + ); + + /** + * Minimum & Maximum provided + */ + cJSON *minimumAndMaximumConfig = cJSON_Parse("{\"minimum\": 6, \"maximum\": 7}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + minimumAndMaximumConfig, + testMinimumAndMaximum + ), + "Failed: should have supplied a random value between a minimum and a maximum" + ); + + /** + * Exclusive minimum provided + */ + cJSON *exclusiveMinimumConfig = cJSON_Parse("{\"exclusiveMinimum\": 99}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + exclusiveMinimumConfig, + testExclusiveMinimum + ), + "Failed: should have supplied a random value above an exclusive minimum" + ); + + /** + * Exclusive maximum provided + */ + cJSON *exclusiveMaximumConfig = cJSON_Parse("{\"exclusiveMaximum\": 1}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + exclusiveMaximumConfig, + testExclusiveMaximum + ), + "Failed: should have supplied a random value below an exclusive maximum" + ); + + /** + * Exclusive minimum & exclusive maximum provided + */ + cJSON *exclusiveMinimumAndMaximumConfig = cJSON_Parse("{\"exclusiveMinimum\": 6, \"exclusiveMaximum\": 8}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + exclusiveMinimumAndMaximumConfig, + testExclusiveMinimumAndMaximum + ), + "Failed: should have supplied a random value between an exclusive minimum and an exclusive maximum" + ); + + /** + * Multiple of provided + */ + cJSON *multipleOfConfig = cJSON_Parse("{\"multipleOf\": 10}"); + mu_assert( + check_number_type_random_function( + "permutate_number", + 0, + multipleOfConfig, + testMultipleOf + ), + "Failed: should have supplied a random value that was a multiple of" + ); + + return NULL; +} + char *all_tests() { mu_suite_start(); mu_run_test(test_dlopen); + mu_run_test(test_number_type); return NULL; } diff --git a/packages/tooling/fast-tooling-wasm/permutator/permutate_number.c b/packages/tooling/fast-tooling-wasm/permutator/permutate_number.c index 3f5c9909640..1fd40e01972 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/permutate_number.c +++ b/packages/tooling/fast-tooling-wasm/permutator/permutate_number.c @@ -1,4 +1,6 @@ #include +#include +#include #include "cjson/cJSON.h" #include "type.h" @@ -14,21 +16,41 @@ double get_random_number(cJSON *configSchema) cJSON *maximum = cJSON_GetObjectItemCaseSensitive(configSchema, "maximum"); cJSON *exclusiveMaximum = cJSON_GetObjectItemCaseSensitive(configSchema, "exclusiveMaximum"); - const int multipleOfValue = multipleOf->valueint - ? multipleOf->valueint + const bool minimumDefined = (minimum && minimum->valuedouble) || (exclusiveMinimum && exclusiveMinimum->valuedouble); + + const bool maximumDefined = (maximum && maximum->valuedouble) || (exclusiveMaximum && exclusiveMaximum->valuedouble); + + const double multipleOfValue = multipleOf && multipleOf->valuedouble + ? multipleOf->valuedouble : 1; - const int minimumValue = minimum->valueint - ? minimum->valueint - : exclusiveMinimum->valueint - ? exclusiveMinimum->valueint + 1 + double minimumValue = minimum && minimum->valuedouble + ? minimum->valuedouble + : exclusiveMinimum && exclusiveMinimum->valuedouble + ? exclusiveMinimum->valuedouble + 1 : 0; - const int maximumValue = maximum->valueint - ? maximum->valueint + 1 - : exclusiveMaximum->valueint - ? exclusiveMaximum->valueint + double maximumValue = maximum && maximum->valuedouble + ? maximum->valuedouble + 1 + : exclusiveMaximum && exclusiveMaximum->valuedouble + ? exclusiveMaximum->valuedouble : 101; - const int randomNumber = (rand() % (maximumValue - minimumValue)) + minimumValue; - const int remainder = randomNumber % multipleOfValue; + + if (maximumDefined && !minimumDefined) + { + minimumValue = maximumValue - 100; + } + + if (!maximumDefined && minimumDefined) + { + maximumValue = minimumValue + 100; + } + + if (minimumValue > maximumValue) + { + return 0; + } + + const double randomNumber = fmod(rand(), (maximumValue - minimumValue)) + minimumValue; + const double remainder = fmod(randomNumber, multipleOfValue); return randomNumber - remainder; } @@ -39,21 +61,21 @@ double get_random_number(cJSON *configSchema) * - if default and/or examples exist, use these before generating any random numbers */ double get_number_iteration_value( - int iteration, + double iteration, enum Type type, cJSON *configSchema ) { - int count = 0; + double count = 0; cJSON *defaultValue = cJSON_GetObjectItemCaseSensitive(configSchema, "default"); cJSON *enumValues = cJSON_GetObjectItemCaseSensitive(configSchema, "enum"); cJSON *exampleValues = cJSON_GetObjectItemCaseSensitive(configSchema, "examples"); if (enumValues != NULL) { - const int arraySize = cJSON_GetArraySize(enumValues); + const double arraySize = cJSON_GetArraySize(enumValues); - return cJSON_GetArrayItem(enumValues, iteration % arraySize)->valuedouble; + return cJSON_GetArrayItem(enumValues, fmod(iteration, arraySize))->valuedouble; } else { if (defaultValue != NULL) { @@ -67,7 +89,7 @@ double get_number_iteration_value( if (exampleValues != NULL) { - const int arraySize = cJSON_GetArraySize(exampleValues); + const double arraySize = cJSON_GetArraySize(exampleValues); if (arraySize + count > iteration) { @@ -91,7 +113,7 @@ struct PermutatedType permutate_number( permutation.type = type; permutation.t.number = get_number_iteration_value( - iteration, + (double) iteration, Number, configSchema ); diff --git a/packages/tooling/fast-tooling-wasm/permutator/type.c b/packages/tooling/fast-tooling-wasm/permutator/type.c index c3faf43cb97..040efb1e3ad 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/type.c +++ b/packages/tooling/fast-tooling-wasm/permutator/type.c @@ -18,5 +18,5 @@ char* get_type_as_string(enum Type type) case Object: return "object"; } - return 0; + return "\0"; } From 152ad4687e52bd7b358fd1ebc20c29b7bb0e0fad Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Mon, 10 Aug 2020 09:40:36 -0700 Subject: [PATCH 2/4] add gcc compiler to workflow --- .github/workflows/ci-daily.yml | 5 +++++ .github/workflows/ci-weekly.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/ci-daily.yml b/.github/workflows/ci-daily.yml index c996e0a6f3f..b41eafd127d 100644 --- a/.github/workflows/ci-daily.yml +++ b/.github/workflows/ci-daily.yml @@ -19,6 +19,11 @@ jobs: steps: - uses: actions/checkout@v2 + - name: gcc + run: | + gcc-8 --version + shell: bash + - name: Add or Update packages run: sudo yarn global add lerna@3.18.2 diff --git a/.github/workflows/ci-weekly.yml b/.github/workflows/ci-weekly.yml index 2970bf65d00..3fe2b40009e 100644 --- a/.github/workflows/ci-weekly.yml +++ b/.github/workflows/ci-weekly.yml @@ -13,6 +13,11 @@ jobs: steps: - uses: actions/checkout@v2 + - name: gcc + run: | + gcc-8 --version + shell: bash + - name: Setup Node.js environment uses: actions/setup-node@v2.1.0 with: From 5d44b7439b8c0b16e2fd05d02f0357d216518797 Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Mon, 10 Aug 2020 09:46:48 -0700 Subject: [PATCH 3/4] address PR comments --- .../permutator/__tests__/test.c | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c b/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c index 31d707a3670..b43ecc9820e 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c +++ b/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c @@ -52,38 +52,37 @@ int check_number_type_random_function( return 0; } -bool testMinimum(double data) +bool test_minimum(double data) { - return data >= 99; } -bool testExclusiveMinimum(double data) +bool test_exclusive_minimum(double data) { return data > 99; } -bool testMaximum(double data) +bool test_maximum(double data) { return data <= 1; } -bool testExclusiveMaximum(double data) +bool test_exclusive_maximum(double data) { return data < 1; } -bool testMinimumAndMaximum(double data) +bool test_minimum_and_maximum(double data) { return data >= 6 && data <= 7; } -bool testExclusiveMinimumAndMaximum(double data) +bool test_exclusive_minimum_and_maximum(double data) { return data > 6 && data < 8; } -bool testMultipleOf(double data) +bool test_multiple_of(double data) { return fmod(data,10) == 0; } @@ -96,6 +95,9 @@ char *test_dlopen() return NULL; } +/** + * Tests the function called when JSON schema is type "number" + */ char *test_number_type() { /** @@ -213,7 +215,7 @@ char *test_number_type() "permutate_number", 0, minimumConfig, - testMinimum + test_minimum ), "Failed: should have supplied a random value above a minimum" ); @@ -227,7 +229,7 @@ char *test_number_type() "permutate_number", 0, maximumConfig, - testMaximum + test_maximum ), "Failed: should have supplied a random value below a maximum" ); @@ -241,7 +243,7 @@ char *test_number_type() "permutate_number", 0, minimumAndMaximumConfig, - testMinimumAndMaximum + test_minimum_and_maximum ), "Failed: should have supplied a random value between a minimum and a maximum" ); @@ -255,7 +257,7 @@ char *test_number_type() "permutate_number", 0, exclusiveMinimumConfig, - testExclusiveMinimum + test_exclusive_minimum ), "Failed: should have supplied a random value above an exclusive minimum" ); @@ -269,7 +271,7 @@ char *test_number_type() "permutate_number", 0, exclusiveMaximumConfig, - testExclusiveMaximum + test_exclusive_maximum ), "Failed: should have supplied a random value below an exclusive maximum" ); @@ -283,7 +285,7 @@ char *test_number_type() "permutate_number", 0, exclusiveMinimumAndMaximumConfig, - testExclusiveMinimumAndMaximum + test_exclusive_minimum_and_maximum ), "Failed: should have supplied a random value between an exclusive minimum and an exclusive maximum" ); @@ -297,7 +299,7 @@ char *test_number_type() "permutate_number", 0, multipleOfConfig, - testMultipleOf + test_multiple_of ), "Failed: should have supplied a random value that was a multiple of" ); From 71969e6b21b476371516657e654db5eaffd621b4 Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Mon, 10 Aug 2020 15:10:46 -0700 Subject: [PATCH 4/4] attempt to ensure fmod math.h is present for compile --- packages/tooling/fast-tooling-wasm/permutator/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tooling/fast-tooling-wasm/permutator/build.js b/packages/tooling/fast-tooling-wasm/permutator/build.js index 633f0536039..35881b94246 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/build.js +++ b/packages/tooling/fast-tooling-wasm/permutator/build.js @@ -18,7 +18,7 @@ const emccFiles = ["wasm.c", "permutate.c"].concat(commonFiles).join(" "); /** * Test file needed for compilation */ -const staticTestFilesCompile = `gcc -Wall -L. "-Wl,-rpath,." -o test test.c -ldl -lpermutate -o test`; +const staticTestFilesCompile = `gcc -Wall -L. "-Wl,-rpath,." -o test test.c -ldl -lpermutate -lm -o test`; const sharedLibSetup = `gcc -Wall -c -fPIC permutate.c -o libpermutate.o`; const sharedLibCompile = `gcc -Wall -shared -fPIC -o libpermutate.so ${commonFiles.join( " "