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: 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..b43ecc9820e 100644 --- a/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c +++ b/packages/tooling/fast-tooling-wasm/permutator/__tests__/test.c @@ -2,27 +2,91 @@ #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 test_minimum(double data) +{ + return data >= 99; +} + +bool test_exclusive_minimum(double data) +{ + return data > 99; +} + +bool test_maximum(double data) +{ + return data <= 1; +} + +bool test_exclusive_maximum(double data) +{ + return data < 1; +} + +bool test_minimum_and_maximum(double data) +{ + return data >= 6 && data <= 7; +} + +bool test_exclusive_minimum_and_maximum(double data) +{ + return data > 6 && data < 8; +} + +bool test_multiple_of(double data) +{ + return fmod(data,10) == 0; +} + char *test_dlopen() { lib = dlopen(lib_file, RTLD_NOW); @@ -31,11 +95,224 @@ char *test_dlopen() return NULL; } +/** + * Tests the function called when JSON schema is type "number" + */ +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, + test_minimum + ), + "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, + test_maximum + ), + "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, + test_minimum_and_maximum + ), + "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, + test_exclusive_minimum + ), + "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, + test_exclusive_maximum + ), + "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, + test_exclusive_minimum_and_maximum + ), + "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, + test_multiple_of + ), + "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/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( " " 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"; }