This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/main by this push:
new 3af7a4654d AVRO-4226: Missing doc attributes for record fields (#3624)
3af7a4654d is described below
commit 3af7a4654d574be7c78125e610a7d4ca23542eab
Author: Mattia Basone <[email protected]>
AuthorDate: Mon Jan 19 07:21:32 2026 +0100
AVRO-4226: Missing doc attributes for record fields (#3624)
* bump composer version
* add missing doc attribute to AvroField
* review + code improvements
* remove AvroNamedSchemata passed by reference
* SchemaTest improvements
* apply Copilot/Martin suggestions
* Update lang/php/lib/Schema/AvroArraySchema.php
Co-authored-by: Martin Grigorov <[email protected]>
---------
Co-authored-by: Martin Grigorov <[email protected]>
---
.github/workflows/test-lang-php.yml | 4 +-
lang/php/lib/Schema/AvroArraySchema.php | 31 +-
lang/php/lib/Schema/AvroEnumSchema.php | 9 +-
lang/php/lib/Schema/AvroField.php | 99 ++-
lang/php/lib/Schema/AvroFixedSchema.php | 6 +-
lang/php/lib/Schema/AvroMapSchema.php | 2 +-
lang/php/lib/Schema/AvroName.php | 3 +-
lang/php/lib/Schema/AvroNamedSchema.php | 4 +-
lang/php/lib/Schema/AvroNamedSchemata.php | 47 +-
lang/php/lib/Schema/AvroRecordSchema.php | 60 +-
lang/php/lib/Schema/AvroSchema.php | 28 +-
lang/php/lib/Schema/AvroUnionSchema.php | 2 +-
lang/php/test/SchemaTest.php | 1314 ++++++++++++++++++++++-------
13 files changed, 1182 insertions(+), 427 deletions(-)
diff --git a/.github/workflows/test-lang-php.yml
b/.github/workflows/test-lang-php.yml
index 5d1a4994b2..faa9454590 100644
--- a/.github/workflows/test-lang-php.yml
+++ b/.github/workflows/test-lang-php.yml
@@ -55,7 +55,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- tools: composer:2.8.12
+ tools: composer:2.9.3
- name: Get Composer Cache Directory
id: composer-cache
@@ -99,7 +99,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- tools: composer:2.8.12
+ tools: composer:2.9.3
- name: Cache Local Maven Repository
uses: actions/cache@v5
diff --git a/lang/php/lib/Schema/AvroArraySchema.php
b/lang/php/lib/Schema/AvroArraySchema.php
index c7c8d9d459..ff8d6563b1 100644
--- a/lang/php/lib/Schema/AvroArraySchema.php
+++ b/lang/php/lib/Schema/AvroArraySchema.php
@@ -27,42 +27,35 @@ namespace Apache\Avro\Schema;
class AvroArraySchema extends AvroSchema
{
/**
- * @var AvroName|AvroSchema named schema name or AvroSchema of
- * array element
+ * @var AvroSchema The schema of the array elements
*/
- private $items;
+ private AvroSchema $items;
- /**
- * @var bool true if the items schema
- * FIXME: couldn't we derive this from whether or not $this->items
- * is an AvroName or an AvroSchema?
- */
- private $is_items_schema_from_schemata;
+ private bool $isItemsSchemaFromSchemata;
/**
* @param mixed|string $items AvroNamedSchema name or object form
* of decoded JSON schema representation.
- * @param string $defaultNamespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata
+ * @throws AvroSchemaParseException
*/
- public function __construct($items, $defaultNamespace, &$schemata = null)
+ public function __construct($items, ?string $defaultNamespace,
AvroNamedSchemata $schemata)
{
parent::__construct(AvroSchema::ARRAY_SCHEMA);
- $this->is_items_schema_from_schemata = false;
- $items_schema = null;
+ $itemsSchema = null;
+ $this->isItemsSchemaFromSchemata = false;
if (
is_string($items)
- && $items_schema = $schemata->schemaByName(
+ && $itemsSchema = $schemata->schemaByName(
new AvroName($items, null, $defaultNamespace)
)
) {
- $this->is_items_schema_from_schemata = true;
+ $this->isItemsSchemaFromSchemata = true;
} else {
- $items_schema = AvroSchema::subparse($items, $defaultNamespace,
$schemata);
+ $itemsSchema = AvroSchema::subparse($items, $defaultNamespace,
$schemata);
}
- $this->items = $items_schema;
+ $this->items = $itemsSchema;
}
/**
@@ -77,7 +70,7 @@ class AvroArraySchema extends AvroSchema
public function toAvro(): string|array
{
$avro = parent::toAvro();
- $avro[AvroSchema::ITEMS_ATTR] = $this->is_items_schema_from_schemata
+ $avro[AvroSchema::ITEMS_ATTR] = $this->isItemsSchemaFromSchemata &&
$this->items instanceof AvroNamedSchema
? $this->items->qualifiedName() : $this->items->toAvro();
return $avro;
diff --git a/lang/php/lib/Schema/AvroEnumSchema.php
b/lang/php/lib/Schema/AvroEnumSchema.php
index dcbcca07e8..8159bfead1 100644
--- a/lang/php/lib/Schema/AvroEnumSchema.php
+++ b/lang/php/lib/Schema/AvroEnumSchema.php
@@ -28,17 +28,14 @@ class AvroEnumSchema extends AvroNamedSchema
/**
* @var string[] array of symbols
*/
- private $symbols;
+ private array $symbols;
/**
- * @param AvroName $name
- * @param string $doc
* @param string[] $symbols
- * @param AvroNamedSchemata &$schemata
- * @param null|mixed $aliases
+ * @param null|array<string> $aliases
* @throws AvroSchemaParseException
*/
- public function __construct($name, $doc, $symbols, &$schemata = null,
$aliases = null)
+ public function __construct(AvroName $name, ?string $doc, mixed $symbols,
AvroNamedSchemata $schemata, ?array $aliases = null)
{
if (!AvroUtil::isList($symbols)) {
throw new AvroSchemaParseException('Enum Schema symbols are not a
list');
diff --git a/lang/php/lib/Schema/AvroField.php
b/lang/php/lib/Schema/AvroField.php
index d7c67e1b0f..2d1510ffc0 100644
--- a/lang/php/lib/Schema/AvroField.php
+++ b/lang/php/lib/Schema/AvroField.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\Schema;
/**
@@ -64,7 +66,7 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
self::IGNORE_SORT_ORDER,
];
- private ?string $name;
+ private string $name;
private bool $isTypeFromSchemata;
@@ -82,24 +84,22 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
*/
private ?string $order;
private ?array $aliases;
+ private ?string $doc;
/**
- * @throws AvroSchemaParseException
+ * @param array<string> $aliases
* @todo Check validity of $default value
*/
- public function __construct(
- ?string $name,
+ private function __construct(
+ string $name,
string|AvroSchema $schema,
bool $isTypeFromSchemata,
bool $hasDefault,
mixed $default,
?string $order = null,
- mixed $aliases = null
+ ?array $aliases = null,
+ ?string $doc = null
) {
- if (!AvroName::isWellFormedName($name)) {
- throw new AvroSchemaParseException('Field requires a "name"
attribute');
- }
-
parent::__construct($schema);
$this->name = $name;
$this->isTypeFromSchemata = $isTypeFromSchemata;
@@ -107,10 +107,63 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
if ($this->hasDefault) {
$this->default = $default;
}
- self::checkOrderValue($order);
$this->order = $order;
- self::hasValidAliases($aliases);
$this->aliases = $aliases;
+
+ $this->doc = $doc;
+ }
+
+ /**
+ * @throws AvroSchemaParseException
+ */
+ public static function fromFieldDefinition(array $avro, ?string
$defaultNamespace, AvroNamedSchemata $schemata): self
+ {
+ $name = $avro[self::FIELD_NAME_ATTR] ?? null;
+ $type = $avro[AvroSchema::TYPE_ATTR] ?? null;
+ $order = $avro[self::ORDER_ATTR] ?? null;
+ $aliases = $avro[AvroSchema::ALIASES_ATTR] ?? null;
+ $doc = $avro[AvroSchema::DOC_ATTR] ?? null;
+
+ if (!AvroName::isWellFormedName($name)) {
+ throw new AvroSchemaParseException('Field requires a "name"
attribute');
+ }
+
+ self::checkOrderValue($order);
+ self::hasValidAliases($aliases);
+ self::hasValidDoc($doc);
+
+ $default = null;
+ $hasDefault = false;
+ if (array_key_exists(self::DEFAULT_ATTR, $avro)) {
+ $default = $avro[self::DEFAULT_ATTR];
+ $hasDefault = true;
+ }
+
+ $isSchemaFromSchemata = false;
+ $fieldAvroSchema = null;
+ if (
+ is_string($type)
+ && $fieldAvroSchema = $schemata->schemaByName(
+ new AvroName($type, null, $defaultNamespace)
+ )
+ ) {
+ $isSchemaFromSchemata = true;
+ } elseif (is_string($type) && self::isPrimitiveType($type)) {
+ $fieldAvroSchema = self::subparse($avro, $defaultNamespace,
$schemata);
+ } else {
+ $fieldAvroSchema = self::subparse($type, $defaultNamespace,
$schemata);
+ }
+
+ return new self(
+ name: $name,
+ schema: $fieldAvroSchema,
+ isTypeFromSchemata: $isSchemaFromSchemata,
+ hasDefault: $hasDefault,
+ default: $default,
+ order: $order,
+ aliases: $aliases,
+ doc: $doc
+ );
}
public function toAvro(): string|array
@@ -131,13 +184,21 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
$avro[self::ORDER_ATTR] = $this->order;
}
+ if (!is_null($this->aliases)) {
+ $avro[AvroSchema::ALIASES_ATTR] = $this->aliases;
+ }
+
+ if (!is_null($this->doc)) {
+ $avro[AvroSchema::DOC_ATTR] = $this->doc;
+ }
+
return $avro;
}
/**
* @returns string the name of this field
*/
- public function name()
+ public function name(): string
{
return $this->name;
}
@@ -153,7 +214,7 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
/**
* @returns boolean true if the field has a default and false otherwise
*/
- public function hasDefaultValue()
+ public function hasDefaultValue(): bool
{
return $this->hasDefault;
}
@@ -163,11 +224,21 @@ class AvroField extends AvroSchema implements
AvroAliasedSchema
return $this->aliases;
}
- public function hasAliases()
+ public function hasAliases(): bool
{
return null !== $this->aliases;
}
+ public function getDoc(): ?string
+ {
+ return $this->doc;
+ }
+
+ public function hasDoc(): bool
+ {
+ return null !== $this->doc;
+ }
+
/**
* @throws AvroSchemaParseException if $order is not a valid
* field order value.
diff --git a/lang/php/lib/Schema/AvroFixedSchema.php
b/lang/php/lib/Schema/AvroFixedSchema.php
index 4cf6e4f794..8fa70fd476 100644
--- a/lang/php/lib/Schema/AvroFixedSchema.php
+++ b/lang/php/lib/Schema/AvroFixedSchema.php
@@ -36,7 +36,7 @@ class AvroFixedSchema extends AvroNamedSchema
* @param int $size byte count of this fixed schema data value
* @throws AvroSchemaParseException
*/
- public function __construct(AvroName $name, ?string $doc, int $size,
?AvroNamedSchemata &$schemata = null, ?array $aliases = null)
+ public function __construct(AvroName $name, ?string $doc, int $size,
AvroNamedSchemata $schemata, ?array $aliases = null)
{
parent::__construct(AvroSchema::FIXED_SCHEMA, $name, $doc, $schemata,
$aliases);
$this->size = $size;
@@ -65,7 +65,7 @@ class AvroFixedSchema extends AvroNamedSchema
public static function duration(
AvroName $name,
?string $doc,
- ?AvroNamedSchemata &$schemata = null,
+ AvroNamedSchemata $schemata,
?array $aliases = null
): self {
$fixedSchema = new self(
@@ -92,7 +92,7 @@ class AvroFixedSchema extends AvroNamedSchema
int $size,
int $precision,
int $scale,
- ?AvroNamedSchemata &$schemata = null,
+ AvroNamedSchemata $schemata,
?array $aliases = null
): self {
$self = new self(
diff --git a/lang/php/lib/Schema/AvroMapSchema.php
b/lang/php/lib/Schema/AvroMapSchema.php
index fc305d5399..32e9e7ba86 100644
--- a/lang/php/lib/Schema/AvroMapSchema.php
+++ b/lang/php/lib/Schema/AvroMapSchema.php
@@ -37,7 +37,7 @@ class AvroMapSchema extends AvroSchema
*/
private bool $isValuesSchemaFromSchemata;
- public function __construct(string|array $values, ?string
$defaultNamespace, ?AvroNamedSchemata &$schemata = null)
+ public function __construct(string|array $values, ?string
$defaultNamespace, AvroNamedSchemata $schemata)
{
parent::__construct(AvroSchema::MAP_SCHEMA);
diff --git a/lang/php/lib/Schema/AvroName.php b/lang/php/lib/Schema/AvroName.php
index bcce7e3a86..a7869b998c 100644
--- a/lang/php/lib/Schema/AvroName.php
+++ b/lang/php/lib/Schema/AvroName.php
@@ -95,9 +95,8 @@ class AvroName implements \Stringable
/**
* @returns boolean true if the given name is well-formed
* (is a non-null, non-empty string) and false otherwise
- * @param mixed $name
*/
- public static function isWellFormedName($name): bool
+ public static function isWellFormedName(mixed $name): bool
{
return is_string($name) && !empty($name) &&
preg_match(self::NAME_REGEXP, $name);
}
diff --git a/lang/php/lib/Schema/AvroNamedSchema.php
b/lang/php/lib/Schema/AvroNamedSchema.php
index e329498a17..4064fbeff8 100644
--- a/lang/php/lib/Schema/AvroNamedSchema.php
+++ b/lang/php/lib/Schema/AvroNamedSchema.php
@@ -32,7 +32,7 @@ class AvroNamedSchema extends AvroSchema implements
AvroAliasedSchema
string $type,
private readonly AvroName $name,
private readonly ?string $doc = null,
- ?AvroNamedSchemata &$schemata = null,
+ ?AvroNamedSchemata $schemata = null,
private ?array $aliases = null
) {
parent::__construct($type);
@@ -42,7 +42,7 @@ class AvroNamedSchema extends AvroSchema implements
AvroAliasedSchema
}
if (!is_null($schemata)) {
- $schemata = $schemata->cloneWithNewSchema($this);
+ $schemata->registerNamedSchema($this);
}
}
diff --git a/lang/php/lib/Schema/AvroNamedSchemata.php
b/lang/php/lib/Schema/AvroNamedSchemata.php
index 37b2b252f3..78912d0ffe 100644
--- a/lang/php/lib/Schema/AvroNamedSchemata.php
+++ b/lang/php/lib/Schema/AvroNamedSchemata.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\Schema;
/**
@@ -34,7 +36,7 @@ class AvroNamedSchemata
) {
}
- public function listSchemas()
+ public function listSchemas(): void
{
var_export($this->schemata);
foreach ($this->schemata as $sch) {
@@ -59,24 +61,37 @@ class AvroNamedSchemata
/**
* Creates a new AvroNamedSchemata instance of this schemata instance
* with the given $schema appended.
+ *
* @param AvroNamedSchema $schema schema to add to this existing schemata
* @throws AvroSchemaParseException
*/
- public function cloneWithNewSchema(AvroNamedSchema $schema):
AvroNamedSchemata
+ public function cloneWithNewSchema(AvroNamedSchema $schema): self
{
$name = $schema->fullname();
- if (AvroSchema::isValidType($name)) {
- throw new AvroSchemaParseException(sprintf('Name "%s" is a
reserved type name', $name));
- }
- if ($this->hasName($name)) {
- throw new AvroSchemaParseException(sprintf('Name "%s" is already
in use', $name));
- }
- $schemata = new AvroNamedSchemata($this->schemata);
+ $this->validateNamedSchema($name);
+
+ $schemata = new self($this->schemata);
$schemata->schemata[$name] = $schema;
return $schemata;
}
+ /**
+ * Append the given AvroNamedSchema to this schemata instance.
+ *
+ * @param AvroNamedSchema $schema schema to add to this existing schemata
+ * @throws AvroSchemaParseException
+ */
+ public function registerNamedSchema(AvroNamedSchema $schema): self
+ {
+ $name = $schema->fullname();
+ $this->validateNamedSchema($name);
+
+ $this->schemata[$name] = $schema;
+
+ return $this;
+ }
+
/**
* @returns bool true if there exists a schema with the given name
* and false otherwise.
@@ -85,4 +100,18 @@ class AvroNamedSchemata
{
return array_key_exists($fullname, $this->schemata);
}
+
+ /**
+ * @throws AvroSchemaParseException
+ */
+ private function validateNamedSchema(string $name): void
+ {
+ if (AvroSchema::isValidType($name)) {
+ throw new AvroSchemaParseException(sprintf('Name "%s" is a
reserved type name', $name));
+ }
+
+ if ($this->hasName($name)) {
+ throw new AvroSchemaParseException(sprintf('Name "%s" is already
in use', $name));
+ }
+ }
}
diff --git a/lang/php/lib/Schema/AvroRecordSchema.php
b/lang/php/lib/Schema/AvroRecordSchema.php
index b234b50cab..c2337a17e2 100644
--- a/lang/php/lib/Schema/AvroRecordSchema.php
+++ b/lang/php/lib/Schema/AvroRecordSchema.php
@@ -37,7 +37,7 @@ class AvroRecordSchema extends AvroNamedSchema
AvroName $name,
?string $doc,
?array $fields,
- ?AvroNamedSchemata &$schemata = null,
+ AvroNamedSchemata $schemata,
string $schema_type = AvroSchema::RECORD_SCHEMA,
?array $aliases = null
) {
@@ -62,64 +62,32 @@ class AvroRecordSchema extends AvroNamedSchema
* @throws AvroSchemaParseException
*/
public static function parseFields(
- array $field_data,
+ array $fieldsDefinitions,
?string $default_namespace,
- ?AvroNamedSchemata $schemata = null
+ AvroNamedSchemata $schemata
): array {
$fields = [];
- $field_names = [];
- $alias_names = [];
- foreach ($field_data as $field) {
- $name = $field[AvroField::FIELD_NAME_ATTR] ?? null;
- $type = $field[AvroSchema::TYPE_ATTR] ?? null;
- $order = $field[AvroField::ORDER_ATTR] ?? null;
- $aliases = $field[AvroSchema::ALIASES_ATTR] ?? null;
-
- $default = null;
- $has_default = false;
- if (array_key_exists(AvroField::DEFAULT_ATTR, $field)) {
- $default = $field[AvroField::DEFAULT_ATTR];
- $has_default = true;
- }
+ $fieldNames = [];
+ $aliasNames = [];
+ foreach ($fieldsDefinitions as $fieldDefinition) {
+ $name = $fieldDefinition[AvroField::FIELD_NAME_ATTR] ?? null;
- if (in_array($name, $field_names)) {
+ if (in_array($name, $fieldNames)) {
throw new AvroSchemaParseException(
sprintf("Field name %s is already in use", $name)
);
}
- $is_schema_from_schemata = false;
- $field_schema = null;
- if (
- is_string($type)
- && $field_schema = $schemata->schemaByName(
- new AvroName($type, null, $default_namespace)
- )
- ) {
- $is_schema_from_schemata = true;
- } elseif (is_string($type) && self::isPrimitiveType($type)) {
- $field_schema = self::subparse($field, $default_namespace,
$schemata);
- } else {
- $field_schema = self::subparse($type, $default_namespace,
$schemata);
- }
+ $newField = AvroField::fromFieldDefinition($fieldDefinition,
$default_namespace, $schemata);
- $new_field = new AvroField(
- name: $name,
- schema: $field_schema,
- isTypeFromSchemata: $is_schema_from_schemata,
- hasDefault: $has_default,
- default: $default,
- order: $order,
- aliases: $aliases
- );
- $field_names[] = $name;
- if ($new_field->hasAliases() && array_intersect($alias_names,
$new_field->getAliases())) {
+ $fieldNames[] = $name;
+ if ($newField->hasAliases() && array_intersect($aliasNames,
$newField->getAliases())) {
throw new AvroSchemaParseException("Alias already in use");
}
- if ($new_field->hasAliases()) {
- array_push($alias_names, ...$new_field->getAliases());
+ if ($newField->hasAliases()) {
+ array_push($aliasNames, ...$newField->getAliases());
}
- $fields[] = $new_field;
+ $fields[] = $newField;
}
return $fields;
diff --git a/lang/php/lib/Schema/AvroSchema.php
b/lang/php/lib/Schema/AvroSchema.php
index 48337d75db..22cc8a5f30 100644
--- a/lang/php/lib/Schema/AvroSchema.php
+++ b/lang/php/lib/Schema/AvroSchema.php
@@ -335,19 +335,15 @@ class AvroSchema implements \Stringable
/**
* @param null|array|string $avro JSON-decoded schema
* @param null|string $default_namespace namespace of enclosing schema
- * @param null|AvroNamedSchemata $schemata reference to named schemas
+ * @param AvroNamedSchemata $schemata reference to named schemas
* @throws AvroSchemaParseException
* @throws AvroException
*/
public static function realParse(
array|string|null $avro,
?string $default_namespace = null,
- ?AvroNamedSchemata &$schemata = null
+ AvroNamedSchemata $schemata = new AvroNamedSchemata()
): AvroSchema {
- if (is_null($schemata)) {
- $schemata = new AvroNamedSchemata();
- }
-
if (is_array($avro)) {
$type = $avro[self::TYPE_ATTR] ?? null;
@@ -384,7 +380,10 @@ class AvroSchema implements \Stringable
$new_name = new AvroName($name, $namespace,
$default_namespace);
$doc = $avro[self::DOC_ATTR] ?? null;
$aliases = $avro[self::ALIASES_ATTR] ?? null;
- AvroNamedSchema::hasValidAliases($aliases);
+
+ self::hasValidAliases($aliases);
+ self::hasValidDoc($doc);
+
switch ($type) {
case self::FIXED_SCHEMA:
$size = $avro[self::SIZE_ATTR] ?? throw new
AvroSchemaParseException(
@@ -544,6 +543,17 @@ class AvroSchema implements \Stringable
}
}
+ public static function hasValidDoc(mixed $doc): void
+ {
+ if (is_string($doc) || is_null($doc)) {
+ return;
+ }
+
+ throw new AvroSchemaParseException(
+ 'Invalid doc value. Must be a string or null.'
+ );
+ }
+
/**
* @returns boolean true if $datum is valid for $expected_schema
* and false otherwise.
@@ -701,12 +711,10 @@ class AvroSchema implements \Stringable
}
/**
- * @param mixed $avro
- * @returns AvroSchema
* @throws AvroSchemaParseException
* @uses AvroSchema::realParse()
*/
- protected static function subparse($avro, ?string $default_namespace,
?AvroNamedSchemata &$schemata = null): AvroSchema
+ protected static function subparse(array|string|null $avro, ?string
$default_namespace, AvroNamedSchemata $schemata): self
{
try {
return self::realParse($avro, $default_namespace, $schemata);
diff --git a/lang/php/lib/Schema/AvroUnionSchema.php
b/lang/php/lib/Schema/AvroUnionSchema.php
index 924af99e44..8220fb6463 100644
--- a/lang/php/lib/Schema/AvroUnionSchema.php
+++ b/lang/php/lib/Schema/AvroUnionSchema.php
@@ -41,7 +41,7 @@ class AvroUnionSchema extends AvroSchema
* @param null|string $defaultNamespace namespace of enclosing schema
* @throws AvroSchemaParseException
*/
- public function __construct(array $schemas, ?string $defaultNamespace,
?AvroNamedSchemata &$schemata = null)
+ public function __construct(array $schemas, ?string $defaultNamespace,
AvroNamedSchemata $schemata)
{
parent::__construct(AvroSchema::UNION_SCHEMA);
diff --git a/lang/php/test/SchemaTest.php b/lang/php/test/SchemaTest.php
index 8a0cb29312..2db5bfd03e 100644
--- a/lang/php/test/SchemaTest.php
+++ b/lang/php/test/SchemaTest.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\Tests;
use Apache\Avro\AvroException;
@@ -28,25 +30,25 @@ use PHPUnit\Framework\TestCase;
class SchemaExample
{
- public $name;
- public $normalized_schema_string;
+ public string $name;
+ public string $normalizedSchemaString;
public function __construct(
- public $schema_string,
- public $is_valid,
- $normalized_schema_string = null,
- $name = null,
- public $comment = null
+ public string $schemaString,
+ public bool $isValid,
+ ?string $normalizedSchemaString = null,
+ ?string $name = null,
+ public ?string $comment = null
) {
- $this->name = $name ?: $this->schema_string;
- $this->normalized_schema_string = $normalized_schema_string ?:
json_encode(json_decode((string) $this->schema_string, true));
+ $this->name = $name ?: $this->schemaString;
+ $this->normalizedSchemaString = $normalizedSchemaString ?:
json_encode(json_decode((string) $this->schemaString, true));
}
}
class SchemaTest extends TestCase
{
- private static $examples = [];
- private static $valid_examples = [];
+ /** @var array<SchemaExample> */
+ private static array $examples = [];
public function test_json_decode(): void
{
@@ -70,6 +72,9 @@ class SchemaTest extends TestCase
$this->assertEquals('boolean', json_decode('"boolean"'));
}
+ /**
+ * @return array<array<SchemaExample>>
+ */
public static function schema_examples_provider(): array
{
self::make_examples();
@@ -82,15 +87,15 @@ class SchemaTest extends TestCase
}
#[DataProvider('schema_examples_provider')]
- public function test_parse($example): void
+ public function test_parse(SchemaExample $example): void
{
- $schema_string = $example->schema_string;
+ $schema_string = $example->schemaString;
try {
- $normalized_schema_string = $example->normalized_schema_string;
+ $normalized_schema_string = $example->normalizedSchemaString;
$schema = AvroSchema::parse($schema_string);
$this->assertTrue(
- $example->is_valid,
+ $example->isValid,
sprintf(
"schema_string: %s\n",
$schema_string
@@ -99,7 +104,7 @@ class SchemaTest extends TestCase
$this->assertEquals($normalized_schema_string, (string) $schema);
} catch (AvroSchemaParseException $e) {
$this->assertFalse(
- $example->is_valid,
+ $example->isValid,
sprintf(
"schema_string: %s\n%s",
$schema_string,
@@ -232,6 +237,47 @@ class SchemaTest extends TestCase
);
}
+ public function test_doc_attribute_on_primitive_fields(): void
+ {
+ $schemaJson = <<<JSON
+ {
+ "type": "record",
+ "name": "fruits",
+ "fields": [
+ {
+ "name": "banana",
+ "type": "string",
+ "doc": "This is a banana"
+ }
+ ]
+ }
+ JSON;
+
+ $schema = AvroSchema::parse($schemaJson);
+
+ self::assertEquals(json_decode($schemaJson, associative: true),
$schema->toAvro());
+ }
+
+ public function test_invalid_doc_attribute_on_field_throws_an_exception():
void
+ {
+ $schemaJson = <<<JSON
+ {
+ "type": "record",
+ "name": "fruits",
+ "fields": [
+ {
+ "name": "banana",
+ "type": "string",
+ "doc": 1
+ }
+ ]
+ }
+ JSON;
+
+ $this->expectException(AvroSchemaParseException::class);
+ AvroSchema::parse($schemaJson);
+ }
+
public function test_logical_types_in_record(): void
{
$avro = <<<JSON
@@ -376,114 +422,230 @@ class SchemaTest extends TestCase
{
$primitive_examples = array_merge(
[
- new SchemaExample('"True"', false),
- new SchemaExample('{"no_type": "test"}', false),
- new SchemaExample('{"type": "panther"}', false),
+ new SchemaExample(
+ '"True"',
+ false
+ ),
+ new SchemaExample(
+ '{"no_type": "test"}',
+ false
+ ),
+ new SchemaExample(
+ '{"type": "panther"}',
+ false
+ ),
],
- self::make_primitive_examples()
+ self::makePrimitiveExamples()
);
$array_examples = [
new SchemaExample('{"type": "array", "items": "long"}', true),
- new SchemaExample('
- {"type": "array",
- "items": {"type": "enum", "name": "Test", "symbols": ["A", "B"]}}
- ', true),
+ new SchemaExample(
+ <<<JSON
+ {
+ "type":"array",
+ "items":{
+ "type":"enum",
+ "name":"Test",
+ "symbols":[
+ "A",
+ "B"
+ ]
+ }
+ }
+ JSON,
+ true
+ ),
];
$map_examples = [
- new SchemaExample('{"type": "map", "values": "long"}', true),
- new SchemaExample('
- {"type": "map",
- "values": {"type": "enum", "name": "Test", "symbols": ["A", "B"]}}
- ', true),
+ new SchemaExample(
+ '{"type": "map", "values": "long"}',
+ true
+ ),
+ new SchemaExample(
+ <<<JSON
+ {
+ "type":"map",
+ "values":{
+ "type":"enum",
+ "name":"Test",
+ "symbols":[
+ "A",
+ "B"
+ ]
+ }
+ }
+ JSON,
+ true
+ ),
];
$union_examples = [
new SchemaExample('["string", "null", "long"]', true),
new SchemaExample('["null", "null"]', false),
new SchemaExample('["long", "long"]', false),
- new SchemaExample('
- [{"type": "array", "items": "long"}
- {"type": "array", "items": "string"}]
- ', false),
- new SchemaExample('["long",
- {"type": "long"},
- "int"]', false),
- new SchemaExample('["long",
- {"type": "array", "items": "long"},
- {"type": "map", "values": "long"},
- "int"]', true),
- new SchemaExample('["long",
- ["string", "null"],
- "int"]', false),
- new SchemaExample('["long",
- ["string", "null"],
- "int"]', false),
new SchemaExample(
- '["null", "boolean", "int", "long", "float", "double",
- "string", "bytes",
- {"type": "array", "items":"int"},
- {"type": "map", "values":"int"},
- {"name": "bar", "type":"record",
- "fields":[{"name":"label", "type":"string"}]},
- {"name": "foo", "type":"fixed",
- "size":16},
- {"name": "baz", "type":"enum", "symbols":["A", "B",
"C"]}
- ]',
+ '[{"type": "array", "items": "long"} {"type": "array",
"items": "string"}]',
+ false
+ ),
+ new SchemaExample(
+ '["long", {"type": "long"}, "int"]',
+ false
+ ),
+ new SchemaExample(
+ <<<JSON
+ [
+ "long",
+ {
+ "type":"array",
+ "items":"long"
+ },
+ {
+ "type":"map",
+ "values":"long"
+ },
+ "int"
+ ]
+ JSON,
+ true
+ ),
+ new SchemaExample(
+ '["long", ["string", "null"], "int"]',
+ false
+ ),
+ new SchemaExample(
+ '["long", ["string", "null"], "int"]',
+ false
+ ),
+ new SchemaExample(
+ <<<JSON
+ [
+ "null",
+ "boolean",
+ "int",
+ "long",
+ "float",
+ "double",
+ "string",
+ "bytes",
+ {
+ "type":"array",
+ "items":"int"
+ },
+ {
+ "type":"map",
+ "values":"int"
+ },
+ {
+ "name":"bar",
+ "type":"record",
+ "fields":[
+ {
+ "name":"label",
+ "type":"string"
+ }
+ ]
+ },
+ {
+ "name":"foo",
+ "type":"fixed",
+ "size":16
+ },
+ {
+ "name":"baz",
+ "type":"enum",
+ "symbols":[
+ "A",
+ "B",
+ "C"
+ ]
+ }
+ ]
+ JSON,
true,
'["null","boolean","int","long","float","double","string","bytes",{"type":"array","items":"int"},{"type":"map","values":"int"},{"type":"record","name":"bar","fields":[{"name":"label","type":"string"}]},{"type":"fixed","name":"foo","size":16},{"type":"enum","name":"baz","symbols":["A","B","C"]}]'
),
new SchemaExample(
- '
- [{"name":"subtract", "namespace":"com.example",
- "type":"record",
- "fields":[{"name":"minuend", "type":"int"},
- {"name":"subtrahend", "type":"int"}]},
- {"name": "divide", "namespace":"com.example",
- "type":"record",
- "fields":[{"name":"quotient", "type":"int"},
- {"name":"dividend", "type":"int"}]},
- {"type": "array", "items": "string"}]
- ',
+ <<<JSON
+ [
+ {
+ "name":"subtract",
+ "namespace":"com.example",
+ "type":"record",
+ "fields":[
+ {
+ "name":"minuend",
+ "type":"int"
+ },
+ {
+ "name":"subtrahend",
+ "type":"int"
+ }
+ ]
+ },
+ {
+ "name":"divide",
+ "namespace":"com.example",
+ "type":"record",
+ "fields":[
+ {
+ "name":"quotient",
+ "type":"int"
+ },
+ {
+ "name":"dividend",
+ "type":"int"
+ }
+ ]
+ },
+ {
+ "type":"array",
+ "items":"string"
+ }
+ ]
+ JSON,
true,
'[{"type":"record","name":"subtract","namespace":"com.example","fields":[{"name":"minuend","type":"int"},{"name":"subtrahend","type":"int"}]},{"type":"record","name":"divide","namespace":"com.example","fields":[{"name":"quotient","type":"int"},{"name":"dividend","type":"int"}]},{"type":"array","items":"string"}]'
),
];
$fixed_examples = [
- new SchemaExample('{"type": "fixed", "name": "Test", "size": 1}',
true),
- new SchemaExample('
- {"type": "fixed",
- "name": "MyFixed",
- "namespace": "org.apache.hadoop.avro",
- "size": 1}
- ', true),
- new SchemaExample('
- {"type": "fixed",
- "name": "Missing size"}
- ', false),
- new SchemaExample('
- {"type": "fixed",
- "size": 314}
- ', false),
+ new SchemaExample(
+ '{"type": "fixed", "name": "Test", "size": 1}',
+ true
+ ),
+ new SchemaExample(
+ <<<JSON
+ {
+ "type":"fixed",
+ "name":"MyFixed",
+ "namespace":"org.apache.hadoop.avro",
+ "size":1
+ }
+ JSON,
+ true
+ ),
+ new SchemaExample(
+ '{"type": "fixed", "name": "Missing size"}',
+ false
+ ),
+ new SchemaExample(
+ '{"type": "fixed", "size": 314}',
+ false
+ ),
new SchemaExample(
'{"type":"fixed","name":"ex","doc":"this shouldn\'t be
ignored","size": 314}',
true,
'{"type":"fixed","name":"ex","doc":"this shouldn\'t be
ignored","size":314}'
),
new SchemaExample(
- '{"name": "bar",
- "namespace": "com.example",
- "type": "fixed",
- "size": 32 }',
+ '{"name": "bar", "namespace": "com.example", "type": "fixed",
"size": 32 }',
true,
'{"type":"fixed","name":"bar","namespace":"com.example","size":32}'
),
new SchemaExample(
- '{"name": "com.example.bar",
- "type": "fixed",
- "size": 32 }',
+ '{"name": "com.example.bar", "type": "fixed", "size": 32}',
true,
'{"type":"fixed","name":"bar","namespace":"com.example","size":32}'
),
@@ -509,258 +671,792 @@ class SchemaTest extends TestCase
);
$enum_examples = [
- new SchemaExample('{"type": "enum", "name": "Test", "symbols":
["A", "B"]}', true),
- new SchemaExample('
- {"type": "enum",
- "name": "Status",
- "symbols": "Normal Caution Critical"}
- ', false),
- new SchemaExample('
- {"type": "enum",
- "name": [ 0, 1, 1, 2, 3, 5, 8 ],
- "symbols": ["Golden", "Mean"]}
- ', false),
- new SchemaExample('
- {"type": "enum",
- "symbols" : ["I", "will", "fail", "no", "name"]}
- ', false),
- new SchemaExample('
- {"type": "enum",
- "name": "Test"
- "symbols" : ["AA", "AA"]}
- ', false),
+ new SchemaExample(
+ '{"type": "enum", "name": "Test", "symbols": ["A", "B"]}',
+ true
+ ),
+ new SchemaExample(
+ '{"type": "enum", "name": "Status", "symbols": "Normal Caution
Critical"}',
+ false
+ ),
+ new SchemaExample(
+ '{"type": "enum", "name": [ 0, 1, 1, 2, 3, 5, 8 ], "symbols":
["Golden", "Mean"]}',
+ false
+ ),
+ new SchemaExample(
+ '{"type": "enum", "symbols" : ["I", "will", "fail", "no",
"name"]}',
+ false
+ ),
+ new SchemaExample(
+ '{"type": "enum", "name": "Test" "symbols" : ["AA", "AA"]}',
+ false
+ ),
new SchemaExample(
'{"type":"enum","name":"Test","symbols":["AA", 16]}',
false
),
- new SchemaExample('
- {"type": "enum",
- "name": "blood_types",
- "doc": "AB is freaky.",
- "symbols" : ["A", "AB", "B", "O"]}
- ', true),
- new SchemaExample('
- {"type": "enum",
- "name": "blood-types",
- "doc": 16,
- "symbols" : ["A", "AB", "B", "O"]}
- ', false),
+ new SchemaExample(
+ <<<JSON
+ {
+ "type":"enum",
+ "name":"blood_types",
+ "doc":"AB is freaky.",
+ "symbols":[
+ "A",
+ "AB",
+ "B",
+ "O"
+ ]
+ }
+ JSON,
+ true
+ ),
+ new SchemaExample(
+ <<<JSON
+ {
+ "type":"enum",
+ "name":"blood-types",
+ "doc":16,
+ "symbols":[
+ "A",
+ "AB",
+ "B",
+ "O"
+ ]
+ }
+ JSON,
+ false
+ ),
];
$record_examples = [];
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Test",
- "fields": [{"name": "f",
- "type": "long"}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "error",
- "name": "Test",
- "fields": [{"name": "f",
- "type": "long"}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Node",
- "fields": [{"name": "label", "type": "string"},
- {"name": "children",
- "type": {"type": "array", "items": "Node"}}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "ListLink",
- "fields": [{"name": "car", "type": "int"},
- {"name": "cdr", "type": "ListLink"}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Lisp",
- "fields": [{"name": "value",
- "type": ["null", "string"]}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Lisp",
- "fields": [{"name": "value",
- "type": ["null", "string",
- {"type": "record",
- "name": "Cons",
- "fields": [{"name": "car", "type": "string"},
- {"name": "cdr", "type": "string"}]}]}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Lisp",
- "fields": [{"name": "value",
- "type": ["null", "string",
- {"type": "record",
- "name": "Cons",
- "fields": [{"name": "car", "type": "Lisp"},
- {"name": "cdr", "type": "Lisp"}]}]}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "HandshakeRequest",
- "namespace": "org.apache.avro.ipc",
- "fields": [{"name": "clientHash",
- "type": {"type": "fixed", "name": "MD5", "size": 16}},
- {"name": "meta",
- "type": ["null", {"type": "map", "values": "bytes"}]}]}
- ', true);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "HandshakeRequest",
- "namespace": "org.apache.avro.ipc",
- "fields": [{"name": "clientHash",
- "type": {"type": "fixed", "name": "MD5", "size": 16}},
- {"name": "clientProtocol", "type": ["null", "string"]},
- {"name": "serverHash", "type": "MD5"},
- {"name": "meta",
- "type": ["null", {"type": "map", "values": "bytes"}]}]}
- ', true);
$record_examples[] = new SchemaExample(
- '
- {"type": "record",
- "name": "HandshakeResponse",
- "namespace": "org.apache.avro.ipc",
- "fields": [{"name": "match",
- "type": {"type": "enum",
- "name": "HandshakeMatch",
- "symbols": ["BOTH", "CLIENT", "NONE"]}},
- {"name": "serverProtocol", "type": ["null", "string"]},
- {"name": "serverHash",
- "type": ["null",
- {"name": "MD5", "size": 16, "type": "fixed"}]},
- {"name": "meta",
- "type": ["null", {"type": "map", "values": "bytes"}]}]}
- ',
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Test",
+ "fields":[
+ {
+ "name":"f",
+ "type":"long"
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"error",
+ "name":"Test",
+ "fields":[
+ {
+ "name":"f",
+ "type":"long"
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Node",
+ "fields":[
+ {
+ "name":"label",
+ "type":"string"
+ },
+ {
+ "name":"children",
+ "type":{
+ "type":"array",
+ "items":"Node"
+ }
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"ListLink",
+ "fields":[
+ {
+ "name":"car",
+ "type":"int"
+ },
+ {
+ "name":"cdr",
+ "type":"ListLink"
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Lisp",
+ "fields":[
+ {
+ "name":"value",
+ "type":[
+ "null",
+ "string"
+ ]
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Lisp",
+ "fields":[
+ {
+ "name":"value",
+ "type":[
+ "null",
+ "string",
+ {
+ "type":"record",
+ "name":"Cons",
+ "fields":[
+ {
+ "name":"car",
+ "type":"string"
+ },
+ {
+ "name":"cdr",
+ "type":"string"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Lisp",
+ "fields":[
+ {
+ "name":"value",
+ "type":[
+ "null",
+ "string",
+ {
+ "type":"record",
+ "name":"Cons",
+ "fields":[
+ {
+ "name":"car",
+ "type":"Lisp"
+ },
+ {
+ "name":"cdr",
+ "type":"Lisp"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"HandshakeRequest",
+ "namespace":"org.apache.avro.ipc",
+ "fields":[
+ {
+ "name":"clientHash",
+ "type":{
+ "type":"fixed",
+ "name":"MD5",
+ "size":16
+ }
+ },
+ {
+ "name":"meta",
+ "type":[
+ "null",
+ {
+ "type":"map",
+ "values":"bytes"
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"HandshakeRequest",
+ "namespace":"org.apache.avro.ipc",
+ "fields":[
+ {
+ "name":"clientHash",
+ "type":{
+ "type":"fixed",
+ "name":"MD5",
+ "size":16
+ }
+ },
+ {
+ "name":"clientProtocol",
+ "type":[
+ "null",
+ "string"
+ ]
+ },
+ {
+ "name":"serverHash",
+ "type":"MD5"
+ },
+ {
+ "name":"meta",
+ "type":[
+ "null",
+ {
+ "type":"map",
+ "values":"bytes"
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
+ true
+ );
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"HandshakeResponse",
+ "namespace":"org.apache.avro.ipc",
+ "fields":[
+ {
+ "name":"match",
+ "type":{
+ "type":"enum",
+ "name":"HandshakeMatch",
+ "symbols":[
+ "BOTH",
+ "CLIENT",
+ "NONE"
+ ]
+ }
+ },
+ {
+ "name":"serverProtocol",
+ "type":[
+ "null",
+ "string"
+ ]
+ },
+ {
+ "name":"serverHash",
+ "type":[
+ "null",
+ {
+ "name":"MD5",
+ "size":16,
+ "type":"fixed"
+ }
+ ]
+ },
+ {
+ "name":"meta",
+ "type":[
+ "null",
+ {
+ "type":"map",
+ "values":"bytes"
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"HandshakeResponse","namespace":"org.apache.avro.ipc","fields":[{"name":"match","type":{"type":"enum","name":"HandshakeMatch","symbols":["BOTH","CLIENT","NONE"]}},{"name":"serverProtocol","type":["null","string"]},{"name":"serverHash","type":["null",{"type":"fixed","name":"MD5","size":16}]},{"name":"meta","type":["null",{"type":"map","values":"bytes"}]}]}'
);
$record_examples[] = new SchemaExample(
- '{"type": "record",
- "namespace": "org.apache.avro",
- "name": "Interop",
- "fields": [{"type": {"fields": [{"type": {"items": "org.apache.avro.Node",
- "type": "array"},
- "name": "children"}],
- "type": "record",
- "name": "Node"},
- "name": "recordField"}]}
-',
+ <<<JSON
+ {
+ "type":"record",
+ "namespace":"org.apache.avro",
+ "name":"Interop",
+ "fields":[
+ {
+ "type":{
+ "fields":[
+ {
+ "type":{
+ "items":"org.apache.avro.Node",
+ "type":"array"
+ },
+ "name":"children"
+ }
+ ],
+ "type":"record",
+ "name":"Node"
+ },
+ "name":"recordField"
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
);
$record_examples[] = new SchemaExample(
- '{"type": "record",
- "namespace": "org.apache.avro",
- "name": "Interop",
- "fields": [{"type": {"symbols": ["A", "B", "C"], "type": "enum", "name":
"Kind"},
- "name": "enumField"},
- {"type": {"fields": [{"type": "string", "name": "label"},
- {"type": {"items": "org.apache.avro.Node",
"type": "array"},
- "name": "children"}],
- "type": "record",
- "name": "Node"},
- "name": "recordField"}]}',
+ <<<JSON
+ {
+ "type":"record",
+ "namespace":"org.apache.avro",
+ "name":"Interop",
+ "fields":[
+ {
+ "type":{
+ "symbols":[
+ "A",
+ "B",
+ "C"
+ ],
+ "type":"enum",
+ "name":"Kind"
+ },
+ "name":"enumField"
+ },
+ {
+ "type":{
+ "fields":[
+ {
+ "type":"string",
+ "name":"label"
+ },
+ {
+ "type":{
+ "items":"org.apache.avro.Node",
+ "type":"array"
+ },
+ "name":"children"
+ }
+ ],
+ "type":"record",
+ "name":"Node"
+ },
+ "name":"recordField"
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
);
$record_examples[] = new SchemaExample(
- '
- {"type": "record",
- "name": "Interop",
- "namespace": "org.apache.avro",
- "fields": [{"name": "intField", "type": "int"},
- {"name": "longField", "type": "long"},
- {"name": "stringField", "type": "string"},
- {"name": "boolField", "type": "boolean"},
- {"name": "floatField", "type": "float"},
- {"name": "doubleField", "type": "double"},
- {"name": "bytesField", "type": "bytes"},
- {"name": "nullField", "type": "null"},
- {"name": "arrayField",
- "type": {"type": "array", "items": "double"}},
- {"name": "mapField",
- "type": {"type": "map",
- "values": {"name": "Foo",
- "type": "record",
- "fields": [{"name": "label",
- "type": "string"}]}}},
- {"name": "unionField",
- "type": ["boolean",
- "double",
- {"type": "array", "items": "bytes"}]},
- {"name": "enumField",
- "type": {"type": "enum",
- "name": "Kind",
- "symbols": ["A", "B", "C"]}},
- {"name": "fixedField",
- "type": {"type": "fixed", "name": "MD5", "size": 16}},
- {"name": "recordField",
- "type": {"type": "record",
- "name": "Node",
- "fields": [{"name": "label", "type": "string"},
- {"name": "children",
- "type": {"type": "array",
- "items": "Node"}}]}}]}
- ',
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Interop",
+ "namespace":"org.apache.avro",
+ "fields":[
+ {
+ "name":"intField",
+ "type":"int"
+ },
+ {
+ "name":"longField",
+ "type":"long"
+ },
+ {
+ "name":"stringField",
+ "type":"string"
+ },
+ {
+ "name":"boolField",
+ "type":"boolean"
+ },
+ {
+ "name":"floatField",
+ "type":"float"
+ },
+ {
+ "name":"doubleField",
+ "type":"double"
+ },
+ {
+ "name":"bytesField",
+ "type":"bytes"
+ },
+ {
+ "name":"nullField",
+ "type":"null"
+ },
+ {
+ "name":"arrayField",
+ "type":{
+ "type":"array",
+ "items":"double"
+ }
+ },
+ {
+ "name":"mapField",
+ "type":{
+ "type":"map",
+ "values":{
+ "name":"Foo",
+ "type":"record",
+ "fields":[
+ {
+ "name":"label",
+ "type":"string"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name":"unionField",
+ "type":[
+ "boolean",
+ "double",
+ {
+ "type":"array",
+ "items":"bytes"
+ }
+ ]
+ },
+ {
+ "name":"enumField",
+ "type":{
+ "type":"enum",
+ "name":"Kind",
+ "symbols":[
+ "A",
+ "B",
+ "C"
+ ]
+ }
+ },
+ {
+ "name":"fixedField",
+ "type":{
+ "type":"fixed",
+ "name":"MD5",
+ "size":16
+ }
+ },
+ {
+ "name":"recordField",
+ "type":{
+ "type":"record",
+ "name":"Node",
+ "fields":[
+ {
+ "name":"label",
+ "type":"string"
+ },
+ {
+ "name":"children",
+ "type":{
+ "type":"array",
+ "items":"Node"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":
[...]
);
+
$record_examples[] = new SchemaExample(
- '{"type": "record", "namespace": "org.apache.avro", "name":
"Interop", "fields": [{"type": "int", "name": "intField"}, {"type": "long",
"name": "longField"}, {"type": "string", "name": "stringField"}, {"type":
"boolean", "name": "boolField"}, {"type": "float", "name": "floatField"},
{"type": "double", "name": "doubleField"}, {"type": "bytes", "name":
"bytesField"}, {"type": "null", "name": "nullField"}, {"type": {"items":
"double", "type": "array"}, "name": "arrayField"}, {"t [...]
-',
+ <<<JSON
+ {
+ "type":"record",
+ "namespace":"org.apache.avro",
+ "name":"Interop",
+ "fields":[
+ {
+ "type":"int",
+ "name":"intField"
+ },
+ {
+ "type":"long",
+ "name":"longField"
+ },
+ {
+ "type":"string",
+ "name":"stringField"
+ },
+ {
+ "type":"boolean",
+ "name":"boolField"
+ },
+ {
+ "type":"float",
+ "name":"floatField"
+ },
+ {
+ "type":"double",
+ "name":"doubleField"
+ },
+ {
+ "type":"bytes",
+ "name":"bytesField"
+ },
+ {
+ "type":"null",
+ "name":"nullField"
+ },
+ {
+ "type":{
+ "items":"double",
+ "type":"array"
+ },
+ "name":"arrayField"
+ },
+ {
+ "type":{
+ "type":"map",
+ "values":{
+ "fields":[
+ {
+ "type":"string",
+ "name":"label"
+ }
+ ],
+ "type":"record",
+ "name":"Foo"
+ }
+ },
+ "name":"mapField"
+ },
+ {
+ "type":[
+ "boolean",
+ "double",
+ {
+ "items":"bytes",
+ "type":"array"
+ }
+ ],
+ "name":"unionField"
+ },
+ {
+ "type":{
+ "symbols":[
+ "A",
+ "B",
+ "C"
+ ],
+ "type":"enum",
+ "name":"Kind"
+ },
+ "name":"enumField"
+ },
+ {
+ "type":{
+ "type":"fixed",
+ "name":"MD5",
+ "size":16
+ },
+ "name":"fixedField"
+ },
+ {
+ "type":{
+ "fields":[
+ {
+ "type":"string",
+ "name":"label"
+ },
+ {
+ "type":{
+ "items":"org.apache.avro.Node",
+ "type":"array"
+ },
+ "name":"children"
+ }
+ ],
+ "type":"record",
+ "name":"Node"
+ },
+ "name":"recordField"
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":
[...]
);
+
$record_examples[] = new SchemaExample(
- '
- {"type": "record",
- "name": "ipAddr",
- "fields": [{"name": "addr",
- "type": [{"name": "IPv6", "type": "fixed", "size": 16},
- {"name": "IPv4", "type": "fixed", "size": 4}]}]}
- ',
+ <<<JSON
+ {
+ "type":"record",
+ "name":"ipAddr",
+ "fields":[
+ {
+ "name":"addr",
+ "type":[
+ {
+ "name":"IPv6",
+ "type":"fixed",
+ "size":16
+ },
+ {
+ "name":"IPv4",
+ "type":"fixed",
+ "size":4
+ }
+ ]
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"ipAddr","fields":[{"name":"addr","type":[{"type":"fixed","name":"IPv6","size":16},{"type":"fixed","name":"IPv4","size":4}]}]}'
);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Address",
- "fields": [{"type": "string"},
- {"type": "string", "name": "City"}]}
- ', false);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "name": "Event",
- "fields": [{"name": "Sponsor"},
- {"name": "City", "type": "string"}]}
- ', false);
- $record_examples[] = new SchemaExample('
- {"type": "record",
- "fields": "His vision, from the constantly passing bars,"
- "name", "Rainer"}
- ', false);
- $record_examples[] = new SchemaExample('
- {"name": ["Tom", "Jerry"],
- "type": "record",
- "fields": [{"name": "name", "type": "string"}]}
- ', false);
+
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Address",
+ "fields":[
+ {
+ "type":"string"
+ },
+ {
+ "type":"string",
+ "name":"City"
+ }
+ ]
+ }
+ JSON,
+ false
+ );
+
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"Event",
+ "fields":[
+ {
+ "name":"Sponsor"
+ },
+ {
+ "name":"City",
+ "type":"string"
+ }
+ ]
+ }
+ JSON,
+ false
+ );
+
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type": "record",
+ "fields": "His vision, from the constantly passing bars,"
+ "name",
+ "Rainer"
+ }
+ JSON,
+ false
+ );
+
$record_examples[] = new SchemaExample(
- '
- {"type":"record","name":"foo","doc":"doc string",
- "fields":[{"name":"bar", "type":"int", "order":"ascending", "default":1}]}
-',
+ <<<JSON
+ {
+ "name":[
+ "Tom",
+ "Jerry"
+ ],
+ "type":"record",
+ "fields":[
+ {
+ "name":"name",
+ "type":"string"
+ }
+ ]
+ }
+ JSON,
+ false
+ );
+
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"foo",
+ "doc":"doc string",
+ "fields":[
+ {
+ "name":"bar",
+ "type":"int",
+ "order":"ascending",
+ "default":1
+ }
+ ]
+ }
+ JSON,
true,
'{"type":"record","name":"foo","doc":"doc
string","fields":[{"name":"bar","type":"int","default":1,"order":"ascending"}]}'
);
- $record_examples[] = new SchemaExample('
- {"type":"record", "name":"foo", "doc":"doc string",
- "fields":[{"name":"bar", "type":"int", "order":"bad"}]}
-', false);
+
+ $record_examples[] = new SchemaExample(
+ <<<JSON
+ {
+ "type":"record",
+ "name":"foo",
+ "doc":"doc string",
+ "fields":[
+ {
+ "name":"bar",
+ "type":"int",
+ "order":"bad"
+ }
+ ]
+ }
+ JSON,
+ false
+ );
+
$record_examples[] = new SchemaExample(
'{"type":"record", "name":"Record2", "aliases":["Record1"]}',
false
@@ -775,15 +1471,9 @@ class SchemaTest extends TestCase
$union_examples,
$record_examples
);
- self::$valid_examples = [];
- foreach (self::$examples as $example) {
- if ($example->is_valid) {
- self::$valid_examples[] = $example;
- }
- }
}
- protected static function make_primitive_examples()
+ protected static function makePrimitiveExamples(): array
{
$examples = [];
foreach ([