From 33f802c6e5d169b582c0361cb0ed61f8b4ae75b0 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 16:54:07 +0200 Subject: [PATCH 01/17] CI: Check immutability of test data --- bin/check-immutability.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 bin/check-immutability.py diff --git a/bin/check-immutability.py b/bin/check-immutability.py new file mode 100644 index 0000000000..4e36773201 --- /dev/null +++ b/bin/check-immutability.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import json +import subprocess +import sys + +oldf = sys.argv[1] +newf = sys.argv[2] + +immutable_keys = ('property', 'input', 'expected') + +# Use jq to flatten the test data, and parse it +old = json.loads(subprocess.run([f"jq -r '[.. | objects | select(.uuid != null)]' {oldf}"], stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')) +new = json.loads(subprocess.run([f"jq -r '[.. | objects | select(.uuid != null)]' {newf}"], stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')) + +# Convert old to dict uuid => case +old = {c['uuid']: c for c in old} + +fails = set() + +for case in new: + if case['uuid'] not in old.keys(): # case is a new test case + continue + + for k in immutable_keys: + if case[k] != old[case['uuid']][k]: + fails.add(case['uuid']) + +if len(fails) == 0: + exit(0) + +print('The following test cases have been illegally mutated:') +for f in fails: + print(f" - {f} ({old[f]['description']})") +exit(1) From b53c12d9be8c6d5a398e177a70a0163909ecf61f Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 16:57:56 +0200 Subject: [PATCH 02/17] Iterate old cases instead --- bin/check-immutability.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 4e36773201..b7b4272c9f 100644 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -13,23 +13,21 @@ old = json.loads(subprocess.run([f"jq -r '[.. | objects | select(.uuid != null)]' {oldf}"], stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')) new = json.loads(subprocess.run([f"jq -r '[.. | objects | select(.uuid != null)]' {newf}"], stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')) -# Convert old to dict uuid => case -old = {c['uuid']: c for c in old} +# Convert new to dict uuid => case +new = {c['uuid']: c for c in new} fails = set() -for case in new: - if case['uuid'] not in old.keys(): # case is a new test case - continue - +# Iterate through old cases as only those could potentially be mutated +for case in old: for k in immutable_keys: - if case[k] != old[case['uuid']][k]: + if case[k] != new[case['uuid']][k]: fails.add(case['uuid']) if len(fails) == 0: exit(0) -print('The following test cases have been illegally mutated:') +print('The following test contain illegal mutations:') for f in fails: - print(f" - {f} ({old[f]['description']})") + print(f" - {f} ({new[f]['description']})") exit(1) From f3a382e416256d68c20a11cd5bac2505ca6248ca Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:05:02 +0200 Subject: [PATCH 03/17] Add to ci.yml workflow --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79d6386991..3736b29330 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,37 @@ jobs: - name: All required files are present run: bin/check_required_files_present + + immutability: + name: No test has been mutated + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + path: 'new' + + # Pull Requests + - name: Checkout the target branch (PRs) + uses: actions/checkout@v2 + if: github.event_name == 'pull_request' + with: + ref: '${{ github.base_ref }}' + path: 'old' + + # Pushes + - name: Checkout the previous commit (Pushes) + uses: actions/checkout@v2 + if: github.event_name == 'push' + with: + ref: '${{ github.sha }}~' + path: 'old' + + - name: Check that no test has been mutated + run: | + for oldf in exercises/*/canonical-data.json; do + newf=${oldf//old/new} + ./bin/check-immutability.py "$oldf" "$newf" + done schema-validation: name: Schema validation From e28ae5930f5bda827b28c478d1b2896b37438eb8 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:08:30 +0200 Subject: [PATCH 04/17] Fix path to python script in workflow --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3736b29330..4d5dc6be1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: run: | for oldf in exercises/*/canonical-data.json; do newf=${oldf//old/new} - ./bin/check-immutability.py "$oldf" "$newf" + ./new/bin/check-immutability.py "$oldf" "$newf" done schema-validation: From b0534972e124e5de47b4214d1c485d6409036c57 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:10:21 +0200 Subject: [PATCH 05/17] Set chmod=+x for python script --- bin/check-immutability.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/check-immutability.py diff --git a/bin/check-immutability.py b/bin/check-immutability.py old mode 100644 new mode 100755 From ff3126fe7d04b6fcc6198015136d384304ee5b3d Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:12:34 +0200 Subject: [PATCH 06/17] Apparently latest does not mean latest --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d5dc6be1f..454de48a56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: immutability: name: No test has been mutated - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: From c1cf71e2c7bea8358792ee857977001cc3cc1fd9 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:19:28 +0200 Subject: [PATCH 07/17] Fix path --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 454de48a56..8134c0e695 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: - name: Check that no test has been mutated run: | - for oldf in exercises/*/canonical-data.json; do + for oldf in old/exercises/*/canonical-data.json; do newf=${oldf//old/new} ./new/bin/check-immutability.py "$oldf" "$newf" done From 18dbfa213e4ee5258c1d6c0cbff790a8e925de26 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:21:10 +0200 Subject: [PATCH 08/17] Test mutated test in PR --- exercises/acronym/canonical-data.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/acronym/canonical-data.json b/exercises/acronym/canonical-data.json index ea52235067..d909bab5da 100644 --- a/exercises/acronym/canonical-data.json +++ b/exercises/acronym/canonical-data.json @@ -9,9 +9,9 @@ "description": "basic", "property": "abbreviate", "input": { - "phrase": "Portable Network Graphics" + "phrase": "Portable Work Graphics" }, - "expected": "PNG" + "expected": "PWG" }, { "uuid": "79ae3889-a5c0-4b01-baf0-232d31180c08", From b4bfd32cab600bb91cfaf56931d7102b00319446 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:23:01 +0200 Subject: [PATCH 09/17] Revert "Test mutated test in PR" This reverts commit 18dbfa213e4ee5258c1d6c0cbff790a8e925de26. --- exercises/acronym/canonical-data.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/acronym/canonical-data.json b/exercises/acronym/canonical-data.json index d909bab5da..ea52235067 100644 --- a/exercises/acronym/canonical-data.json +++ b/exercises/acronym/canonical-data.json @@ -9,9 +9,9 @@ "description": "basic", "property": "abbreviate", "input": { - "phrase": "Portable Work Graphics" + "phrase": "Portable Network Graphics" }, - "expected": "PWG" + "expected": "PNG" }, { "uuid": "79ae3889-a5c0-4b01-baf0-232d31180c08", From 137a9f077566eb5c17309a46b49b66aab1f31e3e Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:26:59 +0200 Subject: [PATCH 10/17] Fix build for workflow_dispatch triggers --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8134c0e695..6d6366240a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: # Pushes - name: Checkout the previous commit (Pushes) uses: actions/checkout@v2 - if: github.event_name == 'push' + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' with: ref: '${{ github.sha }}~' path: 'old' From d8c7384b775bf00181acffdf5feea45c8e2516a0 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:28:10 +0200 Subject: [PATCH 11/17] Break out of loop early on failure --- bin/check-immutability.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index b7b4272c9f..7c71eee620 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -23,6 +23,7 @@ for k in immutable_keys: if case[k] != new[case['uuid']][k]: fails.add(case['uuid']) + break if len(fails) == 0: exit(0) From b578e4c0fe3df9f4504d00cbc9535e60d0769663 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Thu, 15 Oct 2020 17:34:25 +0200 Subject: [PATCH 12/17] Fix typo --- bin/check-immutability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 7c71eee620..740c089bbb 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -28,7 +28,7 @@ if len(fails) == 0: exit(0) -print('The following test contain illegal mutations:') +print('The following tests contain illegal mutations:') for f in fails: print(f" - {f} ({new[f]['description']})") exit(1) From b010ec0614bde40b0403ca599a536e08c723cfc7 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Sat, 17 Oct 2020 12:45:54 +0200 Subject: [PATCH 13/17] Handle removal of tests better --- bin/check-immutability.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 740c089bbb..946d695711 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -17,18 +17,33 @@ new = {c['uuid']: c for c in new} fails = set() +deleted = set() # Iterate through old cases as only those could potentially be mutated for case in old: + uuid = case['uuid'] + + # Check if the case has been deleted + if uuid not in new: + deleted.add(uuid) + continue + for k in immutable_keys: - if case[k] != new[case['uuid']][k]: - fails.add(case['uuid']) + if case[k] != new[uuid][k]: + fails.add(uuid) break -if len(fails) == 0: +if len(fails) == 0 and len(deleted) == 0: exit(0) -print('The following tests contain illegal mutations:') -for f in fails: - print(f" - {f} ({new[f]['description']})") +if len(fails) > 0: + print('The following tests contain illegal mutations:') + for f in fails: + print(f" - {f} ({new[f]['description']})") + +if len(deleted) > 0: + print('The following tests have been deleted illegally:') + for d in deleted: + print(f" - {d}") + exit(1) From af3969ed88e00050bbb2188761f050c3d1f9a8f2 Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Sat, 17 Oct 2020 13:00:49 +0200 Subject: [PATCH 14/17] Add scenarios check --- bin/check-immutability.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 946d695711..1457134eb9 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -28,6 +28,11 @@ deleted.add(uuid) continue + # Check that scenarios are only updated additively + if 'scenarios' in case and not set(case['scenarios']).issubset(set(new[uuid]['scenarios'])): + fails.add(uuid) + + # Check for changes to immutable keys for k in immutable_keys: if case[k] != new[uuid][k]: fails.add(uuid) From 6b6c04236a5f9ec0694fb9ae37db507b7f9c1bec Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Sun, 18 Oct 2020 09:24:24 +0200 Subject: [PATCH 15/17] Update bin/check-immutability.py --- bin/check-immutability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 1457134eb9..9270a27644 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -31,7 +31,7 @@ # Check that scenarios are only updated additively if 'scenarios' in case and not set(case['scenarios']).issubset(set(new[uuid]['scenarios'])): fails.add(uuid) - + continue # Check for changes to immutable keys for k in immutable_keys: if case[k] != new[uuid][k]: From dd2e348669f1abad2fe8b07782de2a17d4f9f9dd Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Mon, 19 Oct 2020 19:10:51 +0200 Subject: [PATCH 16/17] Make variable names longer & use sys.exit instead of exit Co-authored-by: BethanyG Co-authored-by: Corey McCandless Co-authored-by: BethanyG Co-authored-by: Corey McCandless --- bin/check-immutability.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/check-immutability.py b/bin/check-immutability.py index 9270a27644..6f01366ad5 100755 --- a/bin/check-immutability.py +++ b/bin/check-immutability.py @@ -14,7 +14,7 @@ new = json.loads(subprocess.run([f"jq -r '[.. | objects | select(.uuid != null)]' {newf}"], stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8')) # Convert new to dict uuid => case -new = {c['uuid']: c for c in new} +new = {case['uuid']: case for case in new} fails = set() deleted = set() @@ -33,22 +33,22 @@ fails.add(uuid) continue # Check for changes to immutable keys - for k in immutable_keys: - if case[k] != new[uuid][k]: + for key in immutable_keys: + if case[key] != new[uuid][key]: fails.add(uuid) break if len(fails) == 0 and len(deleted) == 0: - exit(0) + sys.exit(0) if len(fails) > 0: print('The following tests contain illegal mutations:') - for f in fails: - print(f" - {f} ({new[f]['description']})") + for failure in fails: + print(f" - {failure} ({new[failure]['description']})") if len(deleted) > 0: print('The following tests have been deleted illegally:') - for d in deleted: - print(f" - {d}") + for deletion in deleted: + print(f" - {deletion}") -exit(1) +sys.exit(1) From ce4ea1124201a95b5b78e8ae94fc09b3eb62006b Mon Sep 17 00:00:00 2001 From: Sascha Mann Date: Tue, 20 Oct 2020 11:27:06 +0200 Subject: [PATCH 17/17] Add test data for future edits to the script --- ...anonical-data-changed-scenarios-after.json | 369 +++++++++++++++++ ...nonical-data-changed-scenarios-before.json | 369 +++++++++++++++++ .../canonical-data-deleted-case.json | 359 +++++++++++++++++ .../canonical-data-mutated-and-deleted.json | 358 +++++++++++++++++ .../canonical-data-mutated.json | 368 +++++++++++++++++ .../canonical-data-new-test.json | 377 ++++++++++++++++++ .../immutability-check/canonical-data.json | 368 +++++++++++++++++ 7 files changed, 2568 insertions(+) create mode 100644 .github/workflow-tests/immutability-check/canonical-data-changed-scenarios-after.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data-changed-scenarios-before.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data-deleted-case.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data-mutated-and-deleted.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data-mutated.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data-new-test.json create mode 100644 .github/workflow-tests/immutability-check/canonical-data.json diff --git a/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-after.json b/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-after.json new file mode 100644 index 0000000000..c13fdabbba --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-after.json @@ -0,0 +1,369 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [1, 0] + }, + "expected": 1 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 1] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "scenarios": ["a", "b"], + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-before.json b/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-before.json new file mode 100644 index 0000000000..9b4f65bfba --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-changed-scenarios-before.json @@ -0,0 +1,369 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [1, 0] + }, + "expected": 1 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 1] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "scenarios": ["a", "b", "c"], + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data-deleted-case.json b/.github/workflow-tests/immutability-check/canonical-data-deleted-case.json new file mode 100644 index 0000000000..83cd8e1861 --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-deleted-case.json @@ -0,0 +1,359 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [1, 0] + }, + "expected": 1 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data-mutated-and-deleted.json b/.github/workflow-tests/immutability-check/canonical-data-mutated-and-deleted.json new file mode 100644 index 0000000000..f93719ffb3 --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-mutated-and-deleted.json @@ -0,0 +1,358 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [2, 0] + }, + "expected": 2 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 2] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data-mutated.json b/.github/workflow-tests/immutability-check/canonical-data-mutated.json new file mode 100644 index 0000000000..f6d695512d --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-mutated.json @@ -0,0 +1,368 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [2, 0] + }, + "expected": 2 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 2] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data-new-test.json b/.github/workflow-tests/immutability-check/canonical-data-new-test.json new file mode 100644 index 0000000000..96f8cfc6a6 --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data-new-test.json @@ -0,0 +1,377 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [1, 0] + }, + "expected": 1 + }, + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7x", + "description": "Real part of a number", + "property": "real", + "input": { + "z": [5, 3] + }, + "expected": 5 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 1] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +} diff --git a/.github/workflow-tests/immutability-check/canonical-data.json b/.github/workflow-tests/immutability-check/canonical-data.json new file mode 100644 index 0000000000..8233b1d2e7 --- /dev/null +++ b/.github/workflow-tests/immutability-check/canonical-data.json @@ -0,0 +1,368 @@ +{ + "exercise": "complex-numbers", + "comments": [ + " The canonical data assumes mathematically correct real ", + " numbers. The testsuites should consider rounding errors ", + " instead of testing for exact values for any non-integer ", + " tests. ", + " Complex numbers z are represented as arrays [x, y] so ", + " that z = x + i * y. ", + " Pi is represented as a string \"pi\", euler's number is ", + " represented as \"e\". " + ], + "cases": [ + { + "description": "Real part", + "cases": [ + { + "uuid": "9f98e133-eb7f-45b0-9676-cce001cd6f7a", + "description": "Real part of a purely real number", + "property": "real", + "input": { + "z": [1, 0] + }, + "expected": 1 + }, + { + "uuid": "07988e20-f287-4bb7-90cf-b32c4bffe0f3", + "description": "Real part of a purely imaginary number", + "property": "real", + "input": { + "z": [0, 1] + }, + "expected": 0 + }, + { + "uuid": "4a370e86-939e-43de-a895-a00ca32da60a", + "description": "Real part of a number with real and imaginary part", + "property": "real", + "input": { + "z": [1, 2] + }, + "expected": 1 + } + ] + }, + { + "description": "Imaginary part", + "cases": [ + { + "uuid": "9b3fddef-4c12-4a99-b8f8-e3a42c7ccef6", + "description": "Imaginary part of a purely real number", + "property": "imaginary", + "input": { + "z": [1, 0] + }, + "expected": 0 + }, + { + "uuid": "a8dafedd-535a-4ed3-8a39-fda103a2b01e", + "description": "Imaginary part of a purely imaginary number", + "property": "imaginary", + "input": { + "z": [0, 1] + }, + "expected": 1 + }, + { + "uuid": "0f998f19-69ee-4c64-80ef-01b086feab80", + "description": "Imaginary part of a number with real and imaginary part", + "property": "imaginary", + "input": { + "z": [1, 2] + }, + "expected": 2 + } + ] + }, + { + "uuid": "a39b7fd6-6527-492f-8c34-609d2c913879", + "description": "Imaginary unit", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 1] + }, + "expected": [-1, 0] + }, + { + "description": "Arithmetic", + "cases": [ + { + "description": "Addition", + "cases": [ + { + "uuid": "9a2c8de9-f068-4f6f-b41c-82232cc6c33e", + "description": "Add purely real numbers", + "property": "add", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [3, 0] + }, + { + "uuid": "657c55e1-b14b-4ba7-bd5c-19db22b7d659", + "description": "Add purely imaginary numbers", + "property": "add", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, 3] + }, + { + "uuid": "4e1395f5-572b-4ce8-bfa9-9a63056888da", + "description": "Add numbers with real and imaginary part", + "property": "add", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [4, 6] + } + ] + }, + { + "description": "Subtraction", + "cases": [ + { + "uuid": "1155dc45-e4f7-44b8-af34-a91aa431475d", + "description": "Subtract purely real numbers", + "property": "sub", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [-1, 0] + }, + { + "uuid": "f95e9da8-acd5-4da4-ac7c-c861b02f774b", + "description": "Subtract purely imaginary numbers", + "property": "sub", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0, -1] + }, + { + "uuid": "f876feb1-f9d1-4d34-b067-b599a8746400", + "description": "Subtract numbers with real and imaginary part", + "property": "sub", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-2, -2] + } + ] + }, + { + "description": "Multiplication", + "cases": [ + { + "uuid": "8a0366c0-9e16-431f-9fd7-40ac46ff4ec4", + "description": "Multiply purely real numbers", + "property": "mul", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [2, 0] + }, + { + "uuid": "e560ed2b-0b80-4b4f-90f2-63cefc911aaf", + "description": "Multiply purely imaginary numbers", + "property": "mul", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [-2, 0] + }, + { + "uuid": "4d1d10f0-f8d4-48a0-b1d0-f284ada567e6", + "description": "Multiply numbers with real and imaginary part", + "property": "mul", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [-5, 10] + } + ] + }, + { + "description": "Division", + "cases": [ + { + "uuid": "b0571ddb-9045-412b-9c15-cd1d816d36c1", + "description": "Divide purely real numbers", + "property": "div", + "input": { + "z1": [1, 0], + "z2": [2, 0] + }, + "expected": [0.5, 0] + }, + { + "uuid": "5bb4c7e4-9934-4237-93cc-5780764fdbdd", + "description": "Divide purely imaginary numbers", + "property": "div", + "input": { + "z1": [0, 1], + "z2": [0, 2] + }, + "expected": [0.5, 0] + }, + { + "uuid": "c4e7fef5-64ac-4537-91c2-c6529707701f", + "description": "Divide numbers with real and imaginary part", + "property": "div", + "input": { + "z1": [1, 2], + "z2": [3, 4] + }, + "expected": [0.44, 0.08] + } + ] + } + ] + }, + { + "description": "Absolute value", + "cases": [ + { + "uuid": "c56a7332-aad2-4437-83a0-b3580ecee843", + "description": "Absolute value of a positive purely real number", + "property": "abs", + "input": { + "z": [5, 0] + }, + "expected": 5 + }, + { + "uuid": "cf88d7d3-ee74-4f4e-8a88-a1b0090ecb0c", + "description": "Absolute value of a negative purely real number", + "property": "abs", + "input": { + "z": [-5, 0] + }, + "expected": 5 + }, + { + "uuid": "bbe26568-86c1-4bb4-ba7a-da5697e2b994", + "description": "Absolute value of a purely imaginary number with positive imaginary part", + "property": "abs", + "input": { + "z": [0, 5] + }, + "expected": 5 + }, + { + "uuid": "3b48233d-468e-4276-9f59-70f4ca1f26f3", + "description": "Absolute value of a purely imaginary number with negative imaginary part", + "property": "abs", + "input": { + "z": [0, -5] + }, + "expected": 5 + }, + { + "uuid": "fe400a9f-aa22-4b49-af92-51e0f5a2a6d3", + "description": "Absolute value of a number with real and imaginary part", + "property": "abs", + "input": { + "z": [3, 4] + }, + "expected": 5 + } + ] + }, + { + "description": "Complex conjugate", + "cases": [ + { + "uuid": "fb2d0792-e55a-4484-9443-df1eddfc84a2", + "description": "Conjugate a purely real number", + "property": "conjugate", + "input": { + "z": [5, 0] + }, + "expected": [5, 0] + }, + { + "uuid": "e37fe7ac-a968-4694-a460-66cb605f8691", + "description": "Conjugate a purely imaginary number", + "property": "conjugate", + "input": { + "z": [0, 5] + }, + "expected": [0, -5] + }, + { + "uuid": "f7704498-d0be-4192-aaf5-a1f3a7f43e68", + "description": "Conjugate a number with real and imaginary part", + "property": "conjugate", + "input": { + "z": [1, 1] + }, + "expected": [1, -1] + } + ] + }, + { + "description": "Complex exponential function", + "comments": [ + " Defining the exponential function can be optional. ", + " If the language used does not have sine and cosine ", + " functions in the standard library, this will be ", + " significantly more difficult than the rest of the exer- ", + " cise and should probably not be part of the problem. ", + " The recommended implementation uses Euler's formula ", + " exp(ix) = cos(x) + i * sin(x). This is not an ideal sol- ", + " ution but works for the purpose of teaching complex ", + " numbers. " + ], + "cases": [ + { + "uuid": "6d96d4c6-2edb-445b-94a2-7de6d4caaf60", + "description": "Euler's identity/formula", + "property": "exp", + "input": { + "z": [0, "pi"] + }, + "expected": [-1, 0] + }, + { + "uuid": "2d2c05a0-4038-4427-a24d-72f6624aa45f", + "description": "Exponential of 0", + "property": "exp", + "input": { + "z": [0, 0] + }, + "expected": [1, 0] + }, + { + "uuid": "ed87f1bd-b187-45d6-8ece-7e331232c809", + "description": "Exponential of a purely real number", + "property": "exp", + "input": { + "z": [1, 0] + }, + "expected": ["e", 0] + }, + { + "uuid": "08eedacc-5a95-44fc-8789-1547b27a8702", + "description": "Exponential of a number with real and imaginary part", + "property": "exp", + "input": { + "z": ["ln(2)", "pi"] + }, + "expected": [-2, 0] + } + ] + } + ] +}