From 0e807a8ddfaf85699d2adb6793da0c42d60956fd Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 31 Oct 2023 11:39:30 +0100 Subject: [PATCH 1/4] Ignore more files in Docker context --- .dockerignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.dockerignore b/.dockerignore index f3ebc2d..1074069 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,3 +7,6 @@ node_modules .gitattributes .dockerignore Dockerfile +test/ +bin/ +!bin/run.sh From 696a61363506adf65bebc9b08d3eec5c6e94b45b Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 31 Oct 2023 11:39:46 +0100 Subject: [PATCH 2/4] Add scripts to run tests --- bin/run-in-docker.sh | 43 +++++++++++++++++++++++++++++++++++++ bin/run-tests-in-docker.sh | 28 ++++++++++++++++++++++++ bin/run-tests.sh | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100755 bin/run-in-docker.sh create mode 100755 bin/run-tests-in-docker.sh create mode 100755 bin/run-tests.sh diff --git a/bin/run-in-docker.sh b/bin/run-in-docker.sh new file mode 100755 index 0000000..8276070 --- /dev/null +++ b/bin/run-in-docker.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env sh + +# Synopsis: +# Run the representer on a solution using the representer Docker image. +# The representer Docker image is built automatically. + +# Arguments: +# $1: exercise slug +# $2: absolute path to solution folder +# $3: absolute path to output directory + +# Output: +# Writes the test results to a results.json file in the passed-in output directory. +# The test results are formatted according to the specifications at https://github.com/exercism/docs/blob/main/building/tooling/representers/interface.md + +# Example: +# ./bin/run-in-docker.sh two-fer /absolute/path/to/two-fer/solution/folder/ /absolute/path/to/output/directory/ + +# If any required arguments is missing, print the usage and exit +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then + echo "usage: ./bin/run-in-docker.sh exercise-slug /absolute/path/to/solution/folder/ /absolute/path/to/output/directory/" + exit 1 +fi + +slug="$1" +input_dir="${2%/}" +output_dir="${3%/}" + +# Create the output directory if it doesn't exist +mkdir -p "${output_dir}" + +# Build the Docker image +docker build --rm -t exercism/typescript-representer . + +# Run the Docker image using the settings mimicking the production environment +docker run \ + --rm \ + --network none \ + --read-only \ + --mount type=bind,source="${input_dir}",destination=/solution \ + --mount type=bind,source="${output_dir}",destination=/output \ + --mount type=tmpfs,destination=/tmp \ + exercism/typescript-representer "${slug}" /solution /output diff --git a/bin/run-tests-in-docker.sh b/bin/run-tests-in-docker.sh new file mode 100755 index 0000000..1799d12 --- /dev/null +++ b/bin/run-tests-in-docker.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env sh + +# Synopsis: +# Test the representer Docker image by running it against a predefined set of +# solutions with an expected output. +# The representer Docker image is built automatically. + +# Output: +# Outputs the diff of the expected representation and mapping against the +# actual representation and mapping generated by the representer. + +# Example: +# ./bin/run-tests-in-docker.sh + +# Build the Docker image +docker build --rm -t exercism/typescript-representer . + +# Run the Docker image using the settings mimicking the production environment +docker run \ + --rm \ + --network none \ + --read-only \ + --mount type=bind,source="${PWD}/test",destination=/opt/representer/test \ + --mount type=tmpfs,destination=/tmp \ + --volume "${PWD}/bin/run-tests.sh:/opt/representer/bin/run-tests.sh" \ + --workdir /opt/representer \ + --entrypoint /opt/representer/bin/run-tests.sh \ + exercism/typescript-representer diff --git a/bin/run-tests.sh b/bin/run-tests.sh new file mode 100755 index 0000000..dfd29da --- /dev/null +++ b/bin/run-tests.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env sh + +# Synopsis: +# Test the representer by running it against a predefined set of solutions +# with an expected output. + +# Output: +# Outputs the diff of the expected representation and mapping against the +# actual representation and mapping generated by the representer. + +# Example: +# ./bin/run-tests.sh + +exit_code=0 + +# We need to copy the fixtures to a temp directory as the user +# running within the Docker container does not have permissions +# to run the sed command on the fixtures directory +fixtures_dir="test/fixtures" +tmp_fixtures_dir="/tmp/test/fixtures" +rm -rf "${tmp_fixtures_dir}" +mkdir -p "${tmp_fixtures_dir}" +cp -R ${fixtures_dir}/* "${tmp_fixtures_dir}" + +# Iterate over all test directories +for test_file in $(find "${tmp_fixtures_dir}" -name '*.test.ts'); do + slug=$(echo "${test_file:${#tmp_fixtures_dir}+1}" | cut -d / -f 1) + test_dir=$(dirname "${test_file}") + test_dir_name=$(basename "${test_dir}") + test_dir_path=$(realpath "${test_dir}") + + bin/run.sh "${slug}" "${test_dir_path}" "${test_dir_path}" + + for file in representation.txt mapping.json; do + expected_file="expected_${file}" + echo "${test_dir_name}: comparing ${file} to ${expected_file}" + + if ! diff "${test_dir_path}/${file}" "${test_dir_path}/${expected_file}"; then + exit_code=1 + fi + done +done + +exit ${exit_code} From b0d29476f2bee2fcddc05e365cd39bacfa251076 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 31 Oct 2023 11:39:52 +0100 Subject: [PATCH 3/4] Run smoke tests in CI --- .github/workflows/ci.js.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.js.yml b/.github/workflows/ci.js.yml index b88c533..83417ba 100644 --- a/.github/workflows/ci.js.yml +++ b/.github/workflows/ci.js.yml @@ -24,7 +24,7 @@ jobs: - name: Lint code run: yarn lint - ci: + unit_tests: runs-on: ubuntu-latest strategy: @@ -40,3 +40,27 @@ jobs: - name: Install project dependencies and run tests run: yarn install --frozen-lockfile + + smoke_tests: + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 + with: + install: true + + - name: Build Docker image and store in cache + uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 + with: + context: . + push: false + load: true + tags: exercism/typescript-representer + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run Tests in Docker + run: bin/run-tests-in-docker.sh From d7206f36651cd767ec94488ace8e411cee80fd4a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 31 Oct 2023 11:41:26 +0100 Subject: [PATCH 4/4] Add smoke tests --- bin/run-tests.sh | 2 +- .../fixtures/clock/pass/expected_mapping.json | 28 + .../clock/pass/expected_representation.txt | 1286 +++++++++++++++++ .../two-fer/error/empty/expected_mapping.json | 1 + .../error/empty/expected_representation.txt | 5 + .../two-fer/fail/expected_mapping.json | 7 + .../two-fer/fail/expected_representation.txt | 140 ++ .../two-fer/pass/expected_mapping.json | 4 + .../two-fer/pass/expected_representation.txt | 77 + 9 files changed, 1549 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/clock/pass/expected_mapping.json create mode 100644 test/fixtures/clock/pass/expected_representation.txt create mode 100644 test/fixtures/two-fer/error/empty/expected_mapping.json create mode 100644 test/fixtures/two-fer/error/empty/expected_representation.txt create mode 100644 test/fixtures/two-fer/fail/expected_mapping.json create mode 100644 test/fixtures/two-fer/fail/expected_representation.txt create mode 100644 test/fixtures/two-fer/pass/expected_mapping.json create mode 100644 test/fixtures/two-fer/pass/expected_representation.txt diff --git a/bin/run-tests.sh b/bin/run-tests.sh index dfd29da..08cbbef 100755 --- a/bin/run-tests.sh +++ b/bin/run-tests.sh @@ -23,7 +23,7 @@ mkdir -p "${tmp_fixtures_dir}" cp -R ${fixtures_dir}/* "${tmp_fixtures_dir}" # Iterate over all test directories -for test_file in $(find "${tmp_fixtures_dir}" -name '*.test.ts'); do +for test_file in $(find "${tmp_fixtures_dir}" -name expected_mapping.json); do slug=$(echo "${test_file:${#tmp_fixtures_dir}+1}" | cut -d / -f 1) test_dir=$(dirname "${test_file}") test_dir_name=$(basename "${test_dir}") diff --git a/test/fixtures/clock/pass/expected_mapping.json b/test/fixtures/clock/pass/expected_mapping.json new file mode 100644 index 0000000..8f5a970 --- /dev/null +++ b/test/fixtures/clock/pass/expected_mapping.json @@ -0,0 +1,28 @@ +{ + "IDENTIFIER_0": "Clock", + "IDENTIFIER_1": "hour", + "IDENTIFIER_2": "minute", + "IDENTIFIER_3": "reset", + "IDENTIFIER_4": "totalMinutes", + "IDENTIFIER_5": "adjustTime", + "IDENTIFIER_6": "getHour", + "IDENTIFIER_7": "getMinute", + "IDENTIFIER_8": "formatNumber", + "IDENTIFIER_9": "numberToFormat", + "IDENTIFIER_10": "numberString", + "IDENTIFIER_11": "length", + "IDENTIFIER_12": "plus", + "IDENTIFIER_13": "minutes", + "IDENTIFIER_14": "minus", + "IDENTIFIER_15": "equals", + "IDENTIFIER_16": "clock", + "IDENTIFIER_17": "delta", + "IDENTIFIER_18": "minutesPerDay", + "IDENTIFIER_19": "minutesPerHour", + "IDENTIFIER_20": "hoursPerDay", + "IDENTIFIER_21": "Math", + "IDENTIFIER_22": "abs", + "IDENTIFIER_23": "currentMinutes", + "IDENTIFIER_24": "newMinutes", + "IDENTIFIER_25": "floor" +} \ No newline at end of file diff --git a/test/fixtures/clock/pass/expected_representation.txt b/test/fixtures/clock/pass/expected_representation.txt new file mode 100644 index 0000000..9882b34 --- /dev/null +++ b/test/fixtures/clock/pass/expected_representation.txt @@ -0,0 +1,1286 @@ +{ + "type": "Program", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_0" + }, + "body": { + "type": "ClassBody", + "body": [ + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "value": null, + "computed": false, + "static": false, + "declare": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + }, + "accessibility": "private", + "definite": true + }, + { + "type": "ClassProperty", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "value": null, + "computed": false, + "static": false, + "declare": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + }, + "accessibility": "private", + "definite": true + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_1", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + }, + { + "type": "AssignmentPattern", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_2", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + }, + "right": { + "type": "Literal", + "value": 0, + "raw": "0" + } + } + ], + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_3" + }, + "computed": false, + "optional": false + }, + "arguments": [], + "optional": false + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_4" + }, + "init": { + "type": "BinaryExpression", + "operator": "+", + "left": { + "type": "BinaryExpression", + "operator": "*", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "right": { + "type": "Literal", + "value": 60, + "raw": "60" + } + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_2" + } + } + } + ], + "kind": "const" + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_5" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Identifier", + "name": "IDENTIFIER_4" + } + ], + "optional": false + } + } + ] + } + }, + "computed": false, + "static": false, + "kind": "constructor" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_3" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "Literal", + "value": 0, + "raw": "0" + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "Literal", + "value": 0, + "raw": "0" + } + } + } + ] + }, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSVoidKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "private" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_6" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + } + } + ] + }, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_7" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + } + } + ] + }, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "TemplateLiteral", + "quasis": [ + { + "type": "TemplateElement", + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "value": { + "raw": ":", + "cooked": ":" + }, + "tail": false + }, + { + "type": "TemplateElement", + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ], + "expressions": [ + { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_8" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + } + ], + "optional": false + }, + { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_8" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + } + ], + "optional": false + } + ] + } + } + ] + }, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSStringKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_8" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_10" + }, + "init": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_9" + }, + "property": { + "type": "Identifier" + }, + "computed": false, + "optional": false + }, + "arguments": [], + "optional": false + } + } + ], + "kind": "const" + }, + { + "type": "ReturnStatement", + "argument": { + "type": "ConditionalExpression", + "test": { + "type": "BinaryExpression", + "operator": "===", + "left": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_10" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_11" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "Literal", + "value": 1, + "raw": "1" + } + }, + "consequent": { + "type": "TemplateLiteral", + "quasis": [ + { + "type": "TemplateElement", + "value": { + "raw": "0", + "cooked": "0" + }, + "tail": false + }, + { + "type": "TemplateElement", + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ], + "expressions": [ + { + "type": "Identifier", + "name": "IDENTIFIER_10" + } + ] + }, + "alternate": { + "type": "Identifier", + "name": "IDENTIFIER_10" + } + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_9", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSStringKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "private" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_12" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_5" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Identifier", + "name": "IDENTIFIER_13" + } + ], + "optional": false + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "ThisExpression" + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_13", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "IDENTIFIER_0" + } + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_14" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_5" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "BinaryExpression", + "operator": "*", + "left": { + "type": "UnaryExpression", + "operator": "-", + "prefix": true, + "argument": { + "type": "Literal", + "value": 1, + "raw": "1" + } + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_13" + } + } + ], + "optional": false + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "ThisExpression" + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_13", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "IDENTIFIER_0" + } + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_15" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "LogicalExpression", + "operator": "&&", + "left": { + "type": "BinaryExpression", + "operator": "===", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_16" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_6" + }, + "computed": false, + "optional": false + }, + "arguments": [], + "optional": false + } + }, + "right": { + "type": "BinaryExpression", + "operator": "===", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_16" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_7" + }, + "computed": false, + "optional": false + }, + "arguments": [], + "optional": false + } + } + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_16", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "IDENTIFIER_0" + } + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSBooleanKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "public" + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "IDENTIFIER_5" + }, + "value": { + "type": "FunctionExpression", + "id": null, + "generator": false, + "expression": false, + "async": false, + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_18" + }, + "init": { + "type": "Literal", + "value": 1440, + "raw": "1440" + } + } + ], + "kind": "const" + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_19" + }, + "init": { + "type": "Literal", + "value": 60, + "raw": "60" + } + } + ], + "kind": "const" + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_20" + }, + "init": { + "type": "Literal", + "value": 24, + "raw": "24" + } + } + ], + "kind": "const" + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_17" + }, + "right": { + "type": "ConditionalExpression", + "test": { + "type": "BinaryExpression", + "operator": ">=", + "left": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_21" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_22" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Identifier", + "name": "IDENTIFIER_17" + } + ], + "optional": false + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_18" + } + }, + "consequent": { + "type": "BinaryExpression", + "operator": "%", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_17" + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_18" + } + }, + "alternate": { + "type": "Identifier", + "name": "IDENTIFIER_17" + } + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_23" + }, + "init": { + "type": "BinaryExpression", + "operator": "+", + "left": { + "type": "BinaryExpression", + "operator": "*", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_19" + } + }, + "right": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + } + } + } + ], + "kind": "const" + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "init": { + "type": "BinaryExpression", + "operator": "%", + "left": { + "type": "BinaryExpression", + "operator": "+", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_23" + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_17" + } + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_18" + } + } + } + ], + "kind": "let" + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "right": { + "type": "ConditionalExpression", + "test": { + "type": "BinaryExpression", + "operator": "<", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "right": { + "type": "Literal", + "value": 0, + "raw": "0" + } + }, + "consequent": { + "type": "AssignmentExpression", + "operator": "+=", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_18" + } + }, + "alternate": { + "type": "Identifier", + "name": "IDENTIFIER_24" + } + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "BinaryExpression", + "operator": "%", + "left": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_21" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_25" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "BinaryExpression", + "operator": "/", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_19" + } + } + ], + "optional": false + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_20" + } + } + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "BinaryExpression", + "operator": "-", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_24" + }, + "right": { + "type": "BinaryExpression", + "operator": "*", + "left": { + "type": "MemberExpression", + "object": { + "type": "ThisExpression" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "computed": false, + "optional": false + }, + "right": { + "type": "Identifier", + "name": "IDENTIFIER_19" + } + } + } + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_17", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSNumberKeyword" + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSVoidKeyword" + } + } + }, + "computed": false, + "static": false, + "kind": "method", + "accessibility": "private" + } + ] + }, + "superClass": null + }, + "specifiers": [], + "source": null, + "exportKind": "value" + } + ], + "sourceType": "module" +} \ No newline at end of file diff --git a/test/fixtures/two-fer/error/empty/expected_mapping.json b/test/fixtures/two-fer/error/empty/expected_mapping.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/test/fixtures/two-fer/error/empty/expected_mapping.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/test/fixtures/two-fer/error/empty/expected_representation.txt b/test/fixtures/two-fer/error/empty/expected_representation.txt new file mode 100644 index 0000000..f41edf3 --- /dev/null +++ b/test/fixtures/two-fer/error/empty/expected_representation.txt @@ -0,0 +1,5 @@ +{ + "type": "Program", + "body": [], + "sourceType": "script" +} \ No newline at end of file diff --git a/test/fixtures/two-fer/fail/expected_mapping.json b/test/fixtures/two-fer/fail/expected_mapping.json new file mode 100644 index 0000000..5f48360 --- /dev/null +++ b/test/fixtures/two-fer/fail/expected_mapping.json @@ -0,0 +1,7 @@ +{ + "IDENTIFIER_0": "twoFer", + "IDENTIFIER_1": "n", + "IDENTIFIER_2": "console", + "IDENTIFIER_3": "debug", + "IDENTIFIER_4": "log" +} \ No newline at end of file diff --git a/test/fixtures/two-fer/fail/expected_representation.txt b/test/fixtures/two-fer/fail/expected_representation.txt new file mode 100644 index 0000000..71f6097 --- /dev/null +++ b/test/fixtures/two-fer/fail/expected_representation.txt @@ -0,0 +1,140 @@ +{ + "type": "Program", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_0" + }, + "init": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [ + { + "type": "Identifier", + "name": "IDENTIFIER_1" + } + ], + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_3" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Identifier", + "name": "IDENTIFIER_1" + } + ], + "optional": false + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "TemplateLiteral", + "quasis": [ + { + "type": "TemplateElement", + "value": { + "raw": "One for you, one for me.", + "cooked": "One for you, one for me." + }, + "tail": true + } + ], + "expressions": [] + } + } + ] + }, + "async": false, + "expression": false + } + } + ], + "kind": "const" + }, + "specifiers": [], + "source": null, + "exportKind": "value" + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_3" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Literal", + "value": "Hello there debug message", + "raw": "\"Hello there debug message\"" + } + ], + "optional": false + } + }, + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "IDENTIFIER_2" + }, + "property": { + "type": "Identifier", + "name": "IDENTIFIER_4" + }, + "computed": false, + "optional": false + }, + "arguments": [ + { + "type": "Literal", + "value": "Ok there log message", + "raw": "\"Ok there log message\"" + } + ], + "optional": false + } + } + ], + "sourceType": "module" +} \ No newline at end of file diff --git a/test/fixtures/two-fer/pass/expected_mapping.json b/test/fixtures/two-fer/pass/expected_mapping.json new file mode 100644 index 0000000..bbec753 --- /dev/null +++ b/test/fixtures/two-fer/pass/expected_mapping.json @@ -0,0 +1,4 @@ +{ + "IDENTIFIER_0": "twoFer", + "IDENTIFIER_1": "name" +} \ No newline at end of file diff --git a/test/fixtures/two-fer/pass/expected_representation.txt b/test/fixtures/two-fer/pass/expected_representation.txt new file mode 100644 index 0000000..dac750a --- /dev/null +++ b/test/fixtures/two-fer/pass/expected_representation.txt @@ -0,0 +1,77 @@ +{ + "type": "Program", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "FunctionDeclaration", + "id": { + "type": "Identifier", + "name": "IDENTIFIER_0" + }, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "AssignmentPattern", + "left": { + "type": "Identifier", + "name": "IDENTIFIER_1" + }, + "right": { + "type": "Literal", + "value": "you", + "raw": "'you'" + } + } + ], + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "TemplateLiteral", + "quasis": [ + { + "type": "TemplateElement", + "value": { + "raw": "One for ", + "cooked": "One for " + }, + "tail": false + }, + { + "type": "TemplateElement", + "value": { + "raw": ", one for me.", + "cooked": ", one for me." + }, + "tail": true + } + ], + "expressions": [ + { + "type": "Identifier", + "name": "IDENTIFIER_1" + } + ] + } + } + ] + }, + "returnType": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSStringKeyword" + } + } + }, + "specifiers": [], + "source": null, + "exportKind": "value" + } + ], + "sourceType": "module" +} \ No newline at end of file