import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import codegen as g
class Naming(unittest.TestCase):
def test_snake_case(self):
cases = {
"jobNo": "job_no", "backofficeID": "backoffice_id", "isMSEntraID": "is_ms_entra_id",
"planningUOM": "planning_uom", "mboc_Id": "mboc_id", "Error": "error",
"freeText1": "free_text1", "siteAddressGeoLong": "site_address_geo_long", "url1": "url1",
}
for src, want in cases.items():
self.assertEqual(g.snake(src), want, src)
def test_keyword_fields_get_trailing_underscore(self):
self.assertEqual(g.field_name("type"), "type_")
self.assertEqual(g.field_name("name"), "name")
def test_rename_needed_only_when_camel_roundtrip_fails(self):
self.assertIsNone(g.serde_rename("jobNo"))
self.assertIsNone(g.serde_rename("freeText1"))
self.assertIsNone(g.serde_rename("type")) self.assertEqual(g.serde_rename("backofficeID"), "backofficeID")
self.assertEqual(g.serde_rename("Error"), "Error")
def test_module_assignment(self):
self.assertEqual(g.module_of("Entities.Task"), ("entities", "Task"))
self.assertEqual(g.module_of("Models.Task"), ("models", "Task"))
self.assertEqual(g.module_of("Core.TaskDto"), ("types", "TaskDto"))
self.assertEqual(
g.module_of("Dime.Scheduler.Api.Models.TaskAssignmentRequest"), ("types", "TaskAssignmentRequest")
)
self.assertEqual(g.module_of("DimeSchedulerApiResponse"), ("types", "DimeSchedulerApiResponse"))
class Types(unittest.TestCase):
def test_scalar_mapping(self):
self.assertEqual(g.rust_type({"type": "string", "format": "date-time"}, {}), "String")
self.assertEqual(g.rust_type({"type": "integer"}, {}), "i32")
self.assertEqual(g.rust_type({"type": "integer", "format": "int64"}, {}), "i64")
self.assertEqual(g.rust_type({"type": "number", "format": "double"}, {}), "f64")
self.assertEqual(g.rust_type({"type": "boolean"}, {}), "bool")
self.assertEqual(g.rust_type({"type": "array", "items": {"type": "string"}}, {}), "Vec<String>")
self.assertEqual(
g.rust_type({"type": "object", "additionalProperties": {"type": "number", "format": "double"}}, {}),
"HashMap<String, f64>",
)
def test_typeless_schema_is_json_value(self):
self.assertEqual(g.rust_type({"nullable": True}, {}), "serde_json::Value")
self.assertEqual(g.rust_type({}, {}), "serde_json::Value")
def test_ref_is_crate_qualified(self):
self.assertEqual(g.rust_type({"$ref": "#/components/schemas/Models.Task"}, {}), "crate::models::Task")
def test_unknown_construct_fails_with_schema_name(self):
with self.assertRaises(SystemExit) as cm:
g.rust_type({"oneOf": [{"type": "string"}]}, {}, where="Entities.Thing.prop")
self.assertIn("Entities.Thing.prop", str(cm.exception))
class Enums(unittest.TestCase):
def test_named_enum(self):
out = g.render_enum("SchedulingMode", "Entities.SchedulingMode",
{"type": "integer", "enum": [0, 1], "x-enumNames": ["Normal", "Manual"]})
self.assertIn("#[repr(i32)]", out)
self.assertIn("#[default]\n Normal = 0,", out)
self.assertIn("Manual = 1,", out)
def test_default_is_lowest_value_not_first_listed(self):
out = g.render_enum("X", "Models.X", {"type": "integer", "enum": [5, 2], "x-enumNames": ["Five", "Two"]})
self.assertIn("#[default]\n Two = 2,", out)
def test_aliased_enum_becomes_newtype(self):
out = g.render_enum("HttpStatusCode", "System.Net.HttpStatusCode",
{"type": "integer", "enum": [300, 301],
"x-enumNames": ["MultipleChoices", "Ambiguous", "MovedPermanently"]})
self.assertIn("pub struct HttpStatusCode(pub i32);", out)
self.assertIn("#[serde(transparent)]", out)
self.assertIn("aliases", out)
class Cycles(unittest.TestCase):
def test_boxes_only_cycle_edges(self):
schemas = {
"Models.A": {"type": "object", "properties": {"b": {"$ref": "#/components/schemas/Models.B"}}},
"Models.B": {"type": "object", "properties": {"a": {"$ref": "#/components/schemas/Models.A"},
"c": {"$ref": "#/components/schemas/Models.C"}}},
"Models.C": {"type": "object", "properties": {"n": {"type": "integer"}}},
}
boxed = g.cycle_edges(schemas)
self.assertIn(("Models.A", "Models.B"), boxed)
self.assertIn(("Models.B", "Models.A"), boxed)
self.assertNotIn(("Models.B", "Models.C"), boxed)
def test_self_reference_is_boxed(self):
schemas = {"Models.T": {"type": "object", "properties": {"parent": {"$ref": "#/components/schemas/Models.T"}}}}
self.assertIn(("Models.T", "Models.T"), g.cycle_edges(schemas))
class Collisions(unittest.TestCase):
def test_duplicate_name_in_module_fails(self):
with self.assertRaises(SystemExit) as cm:
g.plan_modules({"Core.X": {"type": "object"}, "Dime.Scheduler.X": {"type": "object"}})
self.assertIn("types", str(cm.exception))
self.assertIn("X", str(cm.exception))
if __name__ == "__main__":
unittest.main()