From 3c5c5a1ca3c9d9be4290e6ce23c7925d70af927e Mon Sep 17 00:00:00 2001
From: Daniel <d.hornung@indiscale.com>
Date: Mon, 11 Mar 2024 11:34:27 +0100
Subject: [PATCH] WIP: Added (failing) test for indirect reference.

Note: It could be that the real issue is just a problem of reference resolution order..
---
 .../create_jsonschema.py                      |   2 +
 .../data/indirect_data.json                   |  18 +++++
 .../data/indirect_model.yml                   |  18 +++++
 .../data/indirect_schema.json                 |  63 ++++++++++++++++++
 .../data/indirect_template.xlsx               | Bin 0 -> 5853 bytes
 .../table_json_conversion/test_fill_xlsx.py   |   4 ++
 .../test_table_template_generator.py          |  21 +++++-
 7 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 unittests/table_json_conversion/data/indirect_data.json
 create mode 100644 unittests/table_json_conversion/data/indirect_model.yml
 create mode 100644 unittests/table_json_conversion/data/indirect_schema.json
 create mode 100644 unittests/table_json_conversion/data/indirect_template.xlsx

diff --git a/unittests/table_json_conversion/create_jsonschema.py b/unittests/table_json_conversion/create_jsonschema.py
index 07264649..9585f545 100755
--- a/unittests/table_json_conversion/create_jsonschema.py
+++ b/unittests/table_json_conversion/create_jsonschema.py
@@ -67,6 +67,8 @@ def main():
                       do_not_create=["Organisation"])
     prepare_datamodel("data/multiple_refs_model.yml", ["Training", "Person"],
                       "data/multiple_refs_schema.json")
+    prepare_datamodel("data/indirect_model.yml", ["Wrapper"],
+                      "data/indirect_schema.json")
 
 
 if __name__ == "__main__":
diff --git a/unittests/table_json_conversion/data/indirect_data.json b/unittests/table_json_conversion/data/indirect_data.json
new file mode 100644
index 00000000..c77dd1ff
--- /dev/null
+++ b/unittests/table_json_conversion/data/indirect_data.json
@@ -0,0 +1,18 @@
+{
+  "Wrapper": {
+    "Results": [
+      {
+        "year": 2022,
+        "avg_score": 2.4
+      },
+      {
+        "year": 2023,
+        "avg_score": 4.2
+      }
+    ],
+    "Training": {
+      "name": "Basic Training",
+      "url": "www.example.com/training/basic"
+    }
+  }
+}
diff --git a/unittests/table_json_conversion/data/indirect_model.yml b/unittests/table_json_conversion/data/indirect_model.yml
new file mode 100644
index 00000000..2a7f4f98
--- /dev/null
+++ b/unittests/table_json_conversion/data/indirect_model.yml
@@ -0,0 +1,18 @@
+Training:
+  recommended_properties:
+    url:
+      datatype: TEXT
+      description: 'The URL'
+Results:
+  description: "Results for a training"
+  recommended_properties:
+    year:
+      datatype: INTEGER
+    avg_score:
+      description: The average score for the linked training.
+      datatype: DOUBLE
+Wrapper:
+  recommended_properties:
+    Training:
+    Results:
+      datatype: LIST<Results>
diff --git a/unittests/table_json_conversion/data/indirect_schema.json b/unittests/table_json_conversion/data/indirect_schema.json
new file mode 100644
index 00000000..64b6ff27
--- /dev/null
+++ b/unittests/table_json_conversion/data/indirect_schema.json
@@ -0,0 +1,63 @@
+{
+  "type": "object",
+  "properties": {
+    "Wrapper": {
+      "type": "object",
+      "required": [],
+      "additionalProperties": false,
+      "title": "Wrapper",
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "The name of the Record to be created"
+        },
+        "Training": {
+          "type": "object",
+          "required": [],
+          "additionalProperties": false,
+          "title": "Training",
+          "properties": {
+            "name": {
+              "type": "string",
+              "description": "The name of the Record to be created"
+            },
+            "url": {
+              "type": "string",
+              "description": "The URL"
+            }
+          }
+        },
+        "Results": {
+          "description": "Results for a training",
+          "type": "array",
+          "items": {
+            "type": "object",
+            "required": [],
+            "additionalProperties": false,
+            "description": "Results for a training",
+            "title": "Results",
+            "properties": {
+              "name": {
+                "type": "string",
+                "description": "The name of the Record to be created"
+              },
+              "year": {
+                "type": "integer"
+              },
+              "avg_score": {
+                "description": "The average score for the linked training.",
+                "type": "number"
+              }
+            }
+          }
+        }
+      },
+      "$schema": "https://json-schema.org/draft/2020-12/schema"
+    }
+  },
+  "required": [
+    "Wrapper"
+  ],
+  "additionalProperties": false,
+  "$schema": "https://json-schema.org/draft/2020-12/schema"
+}
diff --git a/unittests/table_json_conversion/data/indirect_template.xlsx b/unittests/table_json_conversion/data/indirect_template.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..cc614acb75b36e10143a29f28dff9fce7d5e006f
GIT binary patch
literal 5853
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

literal 0
HcmV?d00001

diff --git a/unittests/table_json_conversion/test_fill_xlsx.py b/unittests/table_json_conversion/test_fill_xlsx.py
index edc723d8..4af73e4d 100644
--- a/unittests/table_json_conversion/test_fill_xlsx.py
+++ b/unittests/table_json_conversion/test_fill_xlsx.py
@@ -78,6 +78,10 @@ def test_fill_xlsx():
                      template_file=rfp("data/multiple_refs_template.xlsx"),
                      known_good=rfp("data/multiple_refs_data.xlsx"),
                      schema=rfp("data/multiple_refs_schema.json"))
+    fill_and_compare(json_file=rfp("data/indirect_data.json"),
+                     template_file=rfp("data/indirect_template.xlsx"),
+                     known_good=rfp("data/multiple_refs_data.xlsx"),
+                     schema=rfp("data/indirect_schema.json"))
 
 
 def test_errors():
diff --git a/unittests/table_json_conversion/test_table_template_generator.py b/unittests/table_json_conversion/test_table_template_generator.py
index b7a2dafc..19cdff2a 100644
--- a/unittests/table_json_conversion/test_table_template_generator.py
+++ b/unittests/table_json_conversion/test_table_template_generator.py
@@ -232,6 +232,25 @@ def test_model_with_multiple_refs():
     _compare_generated_to_known_good(
         schema_file=rfp("data/multiple_refs_schema.json"),
         known_good=rfp("data/multiple_refs_template.xlsx"),
-        foreign_keys={'Training': {"__this__": ['date', 'url'],
+        foreign_keys={"Training": {"__this__": ["date", "url"],
                                    "Organisation": ["name"]}},
         outfile=None)
+
+
+def test_model_with_indirect_reference():
+    _compare_generated_to_known_good(
+        schema_file=rfp("data/indirect_schema.json"),
+        known_good=rfp("data/indirect_template.xlsx"),
+        foreign_keys={"Wrapper": ["Training.name", "Training.url"]},
+        outfile=None)
+
+
+def test_exceptions():
+    # Foreign keys must be lists
+    with pytest.raises(ValueError, match="Foreign keys must be a list of strings, but a single "
+                       r"string was given:\n\['Wrapper'\] -> name"):
+        _compare_generated_to_known_good(
+            schema_file=rfp("data/indirect_schema.json"),
+            known_good=rfp("data/multiple_refs_template.xlsx"),
+            foreign_keys={"Wrapper": {"__this__": "name"}},
+            outfile=None)
-- 
GitLab