diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/schema/document_property_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/schema/document_property_schema_dto.dart index cab42d22f36..5540c1b9e33 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/schema/document_property_schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document/schema/document_property_schema_dto.dart @@ -75,6 +75,31 @@ final class DocumentPropertySchemaDto { required this.pattern, }); + const DocumentPropertySchemaDto.optional({ + this.ref, + this.types, + this.format, + this.contentMediaType, + this.title, + this.description, + this.defaultValue, + this.guidance, + this.constValue, + this.enumValues, + this.properties, + this.items, + this.minimum, + this.maximum, + this.minLength, + this.maxLength, + this.maxItems, + this.minItems, + this.oneOf, + this.required, + this.order, + this.pattern, + }); + factory DocumentPropertySchemaDto.fromJson(Map json) => _$DocumentPropertySchemaDtoFromJson(json); @@ -142,7 +167,7 @@ final class DocumentPropertySchemaDto { isRequired: isRequiredAndNonNullable, ); case DocumentPropertyTypeDto.nullable: - throw ArgumentError('The primary property type cannot be null'); + throw ArgumentError('The primary property type cannot be "null".'); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_definitions_dto_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_definitions_dto_test.dart new file mode 100644 index 00000000000..40dc57e7bf0 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_definitions_dto_test.dart @@ -0,0 +1,53 @@ +import 'package:catalyst_voices_repositories/src/dto/document/schema/document_definitions_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document/schema/document_property_schema_dto.dart'; +import 'package:test/test.dart'; + +void main() { + group(DocumentDefinitionsDto, () { + test('fromJson should create a valid instance from JSON', () { + final json = { + 'def1': {'title': 'Title 1'}, + 'def2': {'title': 'Title 2'}, + }; + + final dto = DocumentDefinitionsDto.fromJson(json); + + expect(dto.getDefinition('def1')?.title, 'Title 1'); + expect(dto.getDefinition('def2')?.title, 'Title 2'); + }); + + test('toJson should convert instance to JSON correctly', () { + final definitions = { + 'def1': const DocumentPropertySchemaDto.optional(title: 'Title 1'), + 'def2': const DocumentPropertySchemaDto.optional(title: 'Title 2'), + }; + + final dto = DocumentDefinitionsDto(definitions); + final json = dto.toJson(); + + expect((json['def1'] as Map)['title'], 'Title 1'); + expect((json['def2'] as Map)['title'], 'Title 2'); + }); + + test('getDefinition should return the correct definition', () { + final definitions = { + 'def1': const DocumentPropertySchemaDto.optional(title: 'Title 1'), + }; + + final dto = DocumentDefinitionsDto(definitions); + + expect(dto.getDefinition('def1')?.title, 'Title 1'); + expect(dto.getDefinition('def2'), isNull); + }); + + test('getDefinition should return null for non-existent definition', () { + final definitions = { + 'def1': const DocumentPropertySchemaDto.optional(title: 'Title 1'), + }; + + final dto = DocumentDefinitionsDto(definitions); + + expect(dto.getDefinition('non_existent'), isNull); + }); + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_property_schema_dto_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_property_schema_dto_test.dart new file mode 100644 index 00000000000..2d7de77e37e --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document/schema/document_property_schema_dto_test.dart @@ -0,0 +1,87 @@ +import 'package:catalyst_voices_repositories/src/dto/document/schema/document_property_schema_dto.dart'; +import 'package:test/test.dart'; + +void main() { + group(DocumentPropertySchemaDto, () { + group('mergeWith', () { + test('should merge two schemas with non-overlapping properties', () { + const schema1 = DocumentPropertySchemaDto.optional( + title: 'Title 1', + description: 'Description 1', + ); + + const schema2 = DocumentPropertySchemaDto.optional( + format: 'Format 2', + contentMediaType: 'Media 2', + ); + + final merged = schema1.mergeWith(schema2); + + expect(merged.title, 'Title 1'); + expect(merged.description, 'Description 1'); + expect(merged.format, 'Format 2'); + expect(merged.contentMediaType, 'Media 2'); + }); + + test('should prefer non-null properties from the original schema', () { + const schema1 = DocumentPropertySchemaDto.optional( + title: 'Title 1', + format: 'Format 1', + ); + + const schema2 = DocumentPropertySchemaDto.optional( + title: 'Title 2', + format: 'Format 2', + ); + + final merged = schema1.mergeWith(schema2); + + expect(merged.title, 'Title 1'); + expect(merged.format, 'Format 1'); + }); + + test('should merge nested properties correctly', () { + const schema1 = DocumentPropertySchemaDto.optional( + properties: { + 'prop1': DocumentPropertySchemaDto.optional(title: 'Prop1 Title'), + }, + ); + + const schema2 = DocumentPropertySchemaDto.optional( + properties: { + 'prop2': DocumentPropertySchemaDto.optional(title: 'Prop2 Title'), + }, + ); + + final merged = schema1.mergeWith(schema2); + + expect(merged.properties!.length, 2); + expect(merged.properties!['prop1']!.title, 'Prop1 Title'); + expect(merged.properties!['prop2']!.title, 'Prop2 Title'); + }); + + test('should merge nested schemas recursively', () { + const schema1 = DocumentPropertySchemaDto.optional( + items: DocumentPropertySchemaDto.optional(title: 'Item Title 1'), + ); + + const schema2 = DocumentPropertySchemaDto.optional( + items: DocumentPropertySchemaDto.optional(title: 'Item Title 2'), + ); + + final merged = schema1.mergeWith(schema2); + + expect(merged.items!.title, 'Item Title 1'); + }); + }); + + group('definition', () { + test('returns the correct ref', () { + const dto = DocumentPropertySchemaDto.optional( + ref: '#/definitions/singleLineTextEntry', + ); + expect(dto.definition(), equals('singleLineTextEntry')); + }); + }); + }); +}