diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35e07689079..0ee93073b39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,5 +24,10 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Test spec normalization + run: | + python3 -m pip install --quiet --break-system-packages pyyaml + python3 -m unittest discover -s scripts -p 'test_*.py' + - name: Build run: mvn compile -q diff --git a/scripts/normalize-spec-for-java.py b/scripts/normalize-spec-for-java.py index 577f1146ed0..1d2fb9f4b77 100755 --- a/scripts/normalize-spec-for-java.py +++ b/scripts/normalize-spec-for-java.py @@ -40,6 +40,12 @@ def collapse_unexpressible_unions(node, path, collapsed): if not isinstance(node, dict): return + items = node.get("items") + if node.get("uniqueItems") and isinstance(items, dict) and "enum" in items: + # native Java's Set addItem helper constructs HashSet. + # Use List; the API still enforces uniqueness on the wire. + del node["uniqueItems"] + for keyword in COMPOSED_KEYWORDS: branches = node.get(keyword) if not isinstance(branches, list): diff --git a/scripts/test_normalize_spec_for_java.py b/scripts/test_normalize_spec_for_java.py new file mode 100644 index 00000000000..d5535fb8444 --- /dev/null +++ b/scripts/test_normalize_spec_for_java.py @@ -0,0 +1,27 @@ +import importlib.util +import unittest +from pathlib import Path + +spec = importlib.util.spec_from_file_location( + 'normalize', Path(__file__).with_name('normalize-spec-for-java.py') +) +normalize = importlib.util.module_from_spec(spec) +spec.loader.exec_module(normalize) + + +class EnumArrayTest(unittest.TestCase): + def test_enum_arrays_use_lists_without_losing_enum_values(self): + schema = {'type': 'array', 'uniqueItems': True, + 'items': {'type': 'string', 'enum': ['whatsapp', 'messenger']}} + normalize.collapse_unexpressible_unions(schema, '$', []) + self.assertNotIn('uniqueItems', schema) + self.assertEqual(schema['items']['enum'], ['whatsapp', 'messenger']) + + def test_non_enum_arrays_keep_set_semantics(self): + schema = {'type': 'array', 'uniqueItems': True, 'items': {'type': 'string'}} + normalize.collapse_unexpressible_unions(schema, '$', []) + self.assertTrue(schema['uniqueItems']) + + +if __name__ == '__main__': + unittest.main()