Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions adcp/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package adcp_test

import (
"os/exec"
"testing"
)

// TestGeneratorPython runs all schema generator Python unit tests. Uses the
// same *_test.py discovery pattern as the CI "Test schema generator" step so
// the two paths stay in sync. Run with: go test ./... from the adcp/ directory.
func TestGeneratorPython(t *testing.T) {
cmd := exec.Command("python3", "-m", "unittest", "discover",
"-s", "schemas", "-p", "*_test.py", "-v")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Python generator tests failed:\n%s", out)
}
t.Logf("Python generator tests:\n%s", out)
}
10 changes: 9 additions & 1 deletion adcp/schemas/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,15 @@ def schema_to_struct(name, schema):
desc = safe_comment(prop.get('description', ''), 80)
comment = f' // {desc}' if desc else ''

fields.append(f'\t{go_name} {go_type} {tag}{comment}')
if prop.get('deprecated', False):
# Strip a leading "Deprecated: " some authors add to description when
# they also set deprecated:true, to avoid "// Deprecated: Deprecated: ..."
raw = re.sub(r'^deprecated:\s*', '', desc, flags=re.IGNORECASE) if desc else ''
deprecated_msg = raw if raw else 'No replacement specified.'
fields.append(f'\t// Deprecated: {deprecated_msg}')
fields.append(f'\t{go_name} {go_type} {tag}')
else:
fields.append(f'\t{go_name} {go_type} {tag}{comment}')

desc = safe_comment(schema.get('description', ''), 100)
doc = f'// {name} — {desc}\n' if desc else ''
Expand Down
114 changes: 114 additions & 0 deletions adcp/schemas/generate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,120 @@
import generate


class TestDeprecatedField(unittest.TestCase):
"""Tests that deprecated: true in a JSON Schema property produces a
preceding // Deprecated: doc comment in the emitted Go struct field."""

def _struct_lines(self, schema):
output = generate.schema_to_struct("TestStruct", schema)
return [l for l in output.splitlines() if l.startswith('\t')]

def test_deprecated_field_emits_preceding_comment(self):
schema = {
"type": "object",
"properties": {
"status": {
"type": "string",
"deprecated": True,
"description": "Use new_status instead.",
}
},
}
lines = self._struct_lines(schema)
self.assertEqual(len(lines), 2,
"Deprecated field should produce exactly 2 lines: comment + field")
self.assertEqual(lines[0], "\t// Deprecated: Use new_status instead.")
self.assertTrue(lines[1].startswith("\tStatus string"),
f"Field line should start with field declaration, got: {lines[1]!r}")
self.assertNotIn("//", lines[1],
"Trailing inline comment suppressed for deprecated fields")

def test_deprecated_field_without_description_uses_fallback(self):
schema = {
"type": "object",
"properties": {
"old_field": {"type": "string", "deprecated": True}
},
}
lines = self._struct_lines(schema)
self.assertEqual(lines[0], "\t// Deprecated: No replacement specified.")

def test_non_deprecated_field_unchanged(self):
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "description": "The display name."}
},
}
lines = self._struct_lines(schema)
self.assertEqual(len(lines), 1,
"Non-deprecated field should produce exactly one line")
self.assertIn("// The display name.", lines[0])

def test_non_deprecated_field_no_description(self):
schema = {
"type": "object",
"properties": {"count": {"type": "integer"}},
}
lines = self._struct_lines(schema)
self.assertEqual(len(lines), 1)
self.assertNotIn("//", lines[0])

def test_mixed_struct_deprecated_and_normal(self):
"""Regression: other fields in the same struct are unaffected."""
schema = {
"type": "object",
"required": ["id"],
"properties": {
"id": {"type": "string", "description": "Unique identifier."},
"status": {
"type": "string",
"deprecated": True,
"description": "Use new_status instead.",
},
"new_status": {"type": "string", "description": "Current status."},
},
}
lines = self._struct_lines(schema)
self.assertEqual(len(lines), 4)
deprecated_comment_idx = next(
(i for i, l in enumerate(lines) if "// Deprecated:" in l), None
)
self.assertIsNotNone(deprecated_comment_idx)
self.assertIn("Status string", lines[deprecated_comment_idx + 1])

def test_deprecated_field_double_prefix_stripped(self):
"""Schema author sets deprecated:true and prefixes description with
'Deprecated: ' — generator must not emit '// Deprecated: Deprecated: …'."""
schema = {
"type": "object",
"properties": {
"axe_include_segment": {
"type": "string",
"deprecated": True,
"description": "Deprecated: Use TMP provider fields instead.",
}
},
}
lines = self._struct_lines(schema)
self.assertEqual(lines[0], "\t// Deprecated: Use TMP provider fields instead.")
self.assertNotIn("Deprecated: Deprecated:", lines[0])

def test_deprecated_case_insensitive_prefix_strip(self):
schema = {
"type": "object",
"properties": {
"old_field": {
"type": "string",
"deprecated": True,
"description": "deprecated: use new_field.",
}
},
}
lines = self._struct_lines(schema)
self.assertEqual(lines[0], "\t// Deprecated: use new_field.")


def scalar_or_array_schema(min_items=1, description="Test union"):
return {
"description": description,
Expand Down
Loading