blob: 319e9a95be31e2fb893be3d5e09756e463e77cfe [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using NUnit.Framework;
using System.Linq;
namespace Avro.Test
{
[TestFixture]
public class SchemaTests
{
// Primitive types - shorthand
[TestCase("null")]
[TestCase("boolean")]
[TestCase("int")]
[TestCase("long")]
[TestCase("float")]
[TestCase("double")]
[TestCase("bytes")]
[TestCase("string")]
[TestCase("\"null\"")]
[TestCase("\"boolean\"")]
[TestCase("\"int\"")]
[TestCase("\"long\"")]
[TestCase("\"float\"")]
[TestCase("\"double\"")]
[TestCase("\"bytes\"")]
[TestCase("\"string\"")]
// Primitive types - longer
[TestCase("{ \"type\": \"null\" }")]
[TestCase("{ \"type\": \"boolean\" }")]
[TestCase("{ \"type\": \"int\" }")]
[TestCase("{ \"type\": \"long\" }")]
[TestCase("{ \"type\": \"float\" }")]
[TestCase("{ \"type\": \"double\" }")]
[TestCase("{ \"type\": \"bytes\" }")]
[TestCase("{ \"type\": \"string\" }")]
// Record
[TestCase("{\"type\": \"record\",\"name\": \"Test\",\"fields\": [{\"name\": \"f\",\"type\": \"long\"}]}")]
[TestCase("{\"type\": \"record\",\"name\": \"Test\",\"fields\": " +
"[{\"name\": \"f1\",\"type\": \"long\"},{\"name\": \"f2\", \"type\": \"int\"}]}")]
[TestCase("{\"type\": \"error\",\"name\": \"Test\",\"fields\": " +
"[{\"name\": \"f1\",\"type\": \"long\"},{\"name\": \"f2\", \"type\": \"int\"}]}")]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"value\",\"type\":\"long\"},{\"name\":\"next\",\"type\":[\"LongList\",\"null\"]}]}")] // Recursive.
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"value\",\"type\":\"long\"},{\"name\":\"next\",\"type\":[\"LongListA\",\"null\"]}]}",
typeof(SchemaParseException), Description = "Unknown name")]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"}",
typeof(SchemaParseException), Description = "No fields")]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\", \"fields\": \"hi\"}",
typeof(SchemaParseException), Description = "Fields not an array")]
[TestCase("[{\"type\": \"record\",\"name\": \"Test\",\"namespace\":\"ns1\",\"fields\": [{\"name\": \"f\",\"type\": \"long\"}]}," +
"{\"type\": \"record\",\"name\": \"Test\",\"namespace\":\"ns2\",\"fields\": [{\"name\": \"f\",\"type\": \"long\"}]}]")]
// Doc
[TestCase("{\"type\": \"record\",\"name\": \"Test\",\"doc\": \"Test Doc\",\"fields\": [{\"name\": \"f\",\"type\": \"long\"}]}")]
// Enum
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}")]
[TestCase("{\"type\": \"enum\", \"name\": \"Status\", \"symbols\": \"Normal Caution Critical\"}",
typeof(SchemaParseException), Description = "Symbols not an array")]
[TestCase("{\"type\": \"enum\", \"name\": [ 0, 1, 1, 2, 3, 5, 8 ], \"symbols\": [\"Golden\", \"Mean\"]}",
typeof(SchemaParseException), Description = "Name not a string")]
[TestCase("{\"type\": \"enum\", \"symbols\" : [\"I\", \"will\", \"fail\", \"no\", \"name\"]}",
typeof(SchemaParseException), Description = "No name")]
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\" : [\"AA\", \"AA\"]}",
typeof(SchemaParseException), Description = "Duplicate symbol")]
// Array
[TestCase("{\"type\": \"array\", \"items\": \"long\"}")]
[TestCase("{\"type\": \"array\",\"items\": {\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}}")]
[TestCase("{\"type\": \"array\"}", typeof(AvroTypeException), Description = "No Items")]
// Map
[TestCase("{\"type\": \"map\", \"values\": \"long\"}")]
[TestCase("{\"type\": \"map\",\"values\": {\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}}")]
// Union
[TestCase("[\"string\", \"null\", \"long\"]")]
[TestCase("[\"string\", \"long\", \"long\"]",
typeof(SchemaParseException), Description = "Duplicate type")]
[TestCase("[{\"type\": \"array\", \"items\": \"long\"}, {\"type\": \"array\", \"items\": \"string\"}]",
typeof(SchemaParseException), Description = "Duplicate type")]
[TestCase("{\"type\":[\"string\", \"null\", \"long\"]}")]
// Fixed
[TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}")]
[TestCase("{\"type\": \"fixed\", \"name\": \"MyFixed\", \"namespace\": \"org.apache.hadoop.avro\", \"size\": 1}")]
[TestCase("{\"type\": \"fixed\", \"name\": \"Missing size\"}", typeof(SchemaParseException))]
[TestCase("{\"type\": \"fixed\", \"size\": 314}",
typeof(SchemaParseException), Description = "No name")]
public void TestBasic(string s, Type expectedExceptionType = null)
{
if (expectedExceptionType != null)
{
Assert.Throws(expectedExceptionType, () => { Schema.Parse(s); });
}
else
{
Schema.Parse(s);
}
}
[TestCase("null", Schema.Type.Null)]
[TestCase("boolean", Schema.Type.Boolean)]
[TestCase("int", Schema.Type.Int)]
[TestCase("long", Schema.Type.Long)]
[TestCase("float", Schema.Type.Float)]
[TestCase("double", Schema.Type.Double)]
[TestCase("bytes", Schema.Type.Bytes)]
[TestCase("string", Schema.Type.String)]
[TestCase("{ \"type\": \"null\" }", Schema.Type.Null)]
[TestCase("{ \"type\": \"boolean\" }", Schema.Type.Boolean)]
[TestCase("{ \"type\": \"int\" }", Schema.Type.Int)]
[TestCase("{ \"type\": \"long\" }", Schema.Type.Long)]
[TestCase("{ \"type\": \"float\" }", Schema.Type.Float)]
[TestCase("{ \"type\": \"double\" }", Schema.Type.Double)]
[TestCase("{ \"type\": \"bytes\" }", Schema.Type.Bytes)]
[TestCase("{ \"type\": \"string\" }", Schema.Type.String)]
public void TestPrimitive(string s, Schema.Type type)
{
Schema sc = Schema.Parse(s);
Schema schema = PrimitiveSchema.Create(type, null);
Assert.AreEqual(sc, schema);
testEquality(s, sc);
testToString(sc);
}
private static void testEquality(string s, Schema sc)
{
Assert.IsTrue(sc.Equals(sc));
Schema sc2 = Schema.Parse(s);
Assert.IsTrue(sc.Equals(sc2));
Assert.AreEqual(sc.GetHashCode(), sc2.GetHashCode());
}
private static void testToString(Schema sc)
{
try
{
Assert.AreEqual(sc, Schema.Parse(sc.ToString()));
}
catch (Exception e)
{
throw new AvroException(e.ToString() + ": " + sc.ToString(), e);
}
}
private static void testToString(Schema sc, string schema)
{
try
{
//remove any excess spaces in the JSON to normalize the match with toString
schema = schema.Replace("{ ", "{")
.Replace("} ", "}")
.Replace("\" ", "\"")
.Replace(", ", ",")
.Replace(": ", ":");
Assert.AreEqual(sc.ToString(), schema);
}
catch (Exception e)
{
throw new AvroException($"{e} : {sc}", e);
}
}
[TestCase("{ \"type\": \"null\", \"metafield\": \"abc\" }", Schema.Type.Null)]
[TestCase("{ \"type\": \"boolean\", \"metafield\": \"abc\" }", Schema.Type.Boolean)]
[TestCase("{ \"type\": \"int\", \"metafield\": \"abc\" }", Schema.Type.Int)]
[TestCase("{ \"type\": \"long\", \"metafield\": \"abc\" }", Schema.Type.Long)]
[TestCase("{ \"type\": \"float\", \"metafield\": \"abc\" }", Schema.Type.Float)]
[TestCase("{ \"type\": \"double\", \"metafield\": \"abc\" }", Schema.Type.Double)]
[TestCase("{ \"type\": \"bytes\", \"metafield\": \"abc\" }", Schema.Type.Bytes)]
[TestCase("{ \"type\": \"string\", \"metafield\": \"abc\" }", Schema.Type.String)]
public void TestPrimitiveWithMetadata(string rawSchema, Schema.Type type)
{
Schema definedSchema = Schema.Parse(rawSchema);
Assert.IsTrue(definedSchema is PrimitiveSchema);
Assert.AreEqual(type.ToString().ToLower(), definedSchema.Name);
Assert.AreEqual(type, definedSchema.Tag);
testEquality(rawSchema, definedSchema);
testToString(definedSchema);
Assert.True(definedSchema.ToString().Contains("metafield"));
var rawRecordSchema = "{\"type\":\"record\",\"name\":\"Foo\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":" + rawSchema +
"}]}";
Schema baseRecordSchema = Schema.Parse(rawRecordSchema);
Assert.AreEqual(Schema.Type.Record, baseRecordSchema.Tag);
RecordSchema recordSchema = baseRecordSchema as RecordSchema;
Assert.IsNotNull(recordSchema);
Assert.AreEqual(1, recordSchema.Count);
Assert.IsTrue(recordSchema["f1"].Schema is PrimitiveSchema);
Assert.AreEqual(type.ToString().ToLower(), recordSchema["f1"].Schema.Name);
Assert.AreEqual(type, recordSchema["f1"].Schema.Tag);
testEquality(rawRecordSchema, baseRecordSchema);
testToString(recordSchema["f1"].Schema);
Assert.True(baseRecordSchema.ToString().Contains("metafield"));
Assert.True(recordSchema["f1"].Schema.ToString().Contains("metafield"));
Assert.True(definedSchema.Equals(recordSchema["f1"].Schema));
Assert.AreEqual(definedSchema.GetHashCode(), recordSchema["f1"].Schema.GetHashCode());
}
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":\"long\"}," +
"{\"name\":\"f2\",\"type\": \"int\"}]}",
new string[] { "f1", "long", "100", "f2", "int", "10" })]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":\"long\", \"default\": \"100\"}," +
"{\"name\":\"f2\",\"type\": \"int\"}]}",
new string[] { "f1", "long", "100", "f2", "int", "10" })]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"value\",\"type\":\"long\", \"default\": \"100\"}," +
"{\"name\":\"next\",\"type\":[\"LongList\",\"null\"]}]}",
new string[] { "value", "long", "100", "next", "union", null })]
public void TestRecord(string s, string[] kv)
{
Schema sc = Schema.Parse(s);
Assert.AreEqual(Schema.Type.Record, sc.Tag);
RecordSchema rs = sc as RecordSchema;
Assert.AreEqual(kv.Length / 3, rs.Count);
for (int i = 0; i < kv.Length; i += 3)
{
Field f = rs[kv[i]];
Assert.AreEqual(kv[i + 1], f.Schema.Name);
/*
if (kv[i + 2] != null)
{
Assert.IsNotNull(f.DefaultValue);
Assert.AreEqual(kv[i + 2], f.DefaultValue);
}
else
{
Assert.IsNull(f.DefaultValue);
}
*/
}
testEquality(s, sc);
testToString(sc);
}
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":\"long\"}," +
"{\"name\":\"f2\",\"type\": \"int\"}]}",
null)]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":\"long\", \"default\": \"100\"}," +
"{\"name\":\"f2\",\"type\": \"int\"}], \"doc\": \"\"}",
"")]
[TestCase("{\"type\":\"record\",\"name\":\"LongList\"," +
"\"fields\":[{\"name\":\"f1\",\"type\":\"long\", \"default\": \"100\"}," +
"{\"name\":\"f2\",\"type\": \"int\"}], \"doc\": \"this is a test\"}",
"this is a test")]
public void TestRecordDoc(string s, string expectedDoc)
{
var rs = Schema.Parse(s) as RecordSchema;
Assert.IsNotNull(rs);
Assert.AreEqual(expectedDoc, rs.Documentation);
var roundTrip = Schema.Parse(rs.ToString()) as RecordSchema;
Assert.IsNotNull(roundTrip);
Assert.AreEqual(expectedDoc, roundTrip.Documentation);
}
[TestCase("{\"type\":\"record\",\"name\":\"Longs\",\"fields\":[{\"name\":\"value\",\"default\":\"100\",\"type\":\"long\",\"aliases\":[\"oldName\"]}]}",
"Longs", null, null, null,
new[] { "value" }, new[] { Schema.Type.Long }, new[] { "100" }, new[] { "oldName" }, new string[] { null })]
[TestCase("{\"type\":\"record\",\"name\":\"Longs\",\"fields\":[{\"name\":\"value\",\"doc\":\"Field With Documentation\",\"default\":\"100\",\"type\":\"long\",\"aliases\":[\"oldName\"]}]}",
"Longs", null, null, null,
new[] { "value" }, new[] { Schema.Type.Long }, new[] { "100" }, new[] { "oldName" }, new string[] { "Field With Documentation" })]
[TestCase("{\"type\":\"record\",\"name\":\"Longs\",\"namespace\":\"space\",\"fields\":[{\"name\":\"value\",\"default\":\"100\",\"type\":\"long\",\"aliases\":[\"oldName\"]}]}",
"Longs", "space", null, null,
new[] { "value" }, new[] { Schema.Type.Long }, new[] { "100" }, new[] { "oldName" }, new string[] { null })]
[TestCase("{\"type\":\"record\",\"name\":\"Longs\",\"doc\":\"Record with alias\",\"namespace\":\"space\",\"aliases\":[\"space.RecordAlias\"],\"fields\":[{\"name\":\"value\",\"default\":\"100\",\"type\":\"long\",\"aliases\":[\"oldName\"]}]}",
"Longs", "space", "RecordAlias", "Record with alias",
new[] { "value" }, new[] { Schema.Type.Long }, new[] { "100" }, new[] { "oldName" }, new string[] { null })]
[TestCase("{\"type\":\"record\",\"name\":\"Longs\",\"doc\":\"Record with two fields\",\"namespace\":\"space\",\"aliases\":[\"space.RecordAlias\"],\"fields\":[{\"name\":\"value\",\"doc\":\"first field\",\"default\":\"100\",\"type\":\"long\",\"aliases\":[\"oldName\"]},{\"name\":\"field2\",\"default\":\"true\",\"type\":\"boolean\"}]}",
"Longs", "space", "RecordAlias", "Record with two fields",
new[] { "value", "field2" }, new[] { Schema.Type.Long, Schema.Type.Boolean }, new[] { "100", "true" }, new[] { "oldName", null }, new string[] { "first field", null })]
public void TestRecordCreation(string expectedSchema, string name, string space, string alias, string documentation, string[] fieldsNames, Schema.Type[] fieldsTypes, object[] fieldsDefaultValues, string[] fieldsAliases, string[] fieldsDocs)
{
IEnumerable<Field> recordFields = fieldsNames.Select((fieldName, i) => new Field(PrimitiveSchema.Create(fieldsTypes[i]),
fieldName,
fieldsAliases[i] == null? null: new List<string> { fieldsAliases[i] },
i,
fieldsDocs[i],
fieldsDefaultValues[i].ToString(),
Field.SortOrder.ignore,
null));
string[] aliases = alias == null ? null : new[] { alias };
RecordSchema recordSchema = RecordSchema.Create(name, recordFields.ToList(), space, aliases, null, documentation);
for(int i = 0; i < fieldsNames.Length; i++)
{
var fieldByName = recordSchema[fieldsNames[i]];
if (fieldsAliases[i] != null)
{
recordSchema.TryGetFieldAlias(fieldsAliases[i], out Field fieldByAlias);
Assert.AreSame(fieldByAlias, fieldByName);
}
Assert.AreEqual(expectedSchema, recordSchema.ToString());
Assert.AreEqual(fieldsNames[i], fieldByName.Name);
Assert.AreEqual(i, fieldByName.Pos);
Assert.AreEqual(fieldsTypes[i], fieldByName.Schema.Tag);
Assert.AreEqual(fieldsDocs[i], fieldByName.Documentation);
Assert.AreEqual(fieldsDefaultValues[i], fieldByName.DefaultValue.ToString());
CollectionAssert.AreEqual(fieldsAliases[i] == null? null: new[] {fieldsAliases[i]}, fieldByName.Aliases);
}
}
[TestCase]
public void TestRecordCreationWithDuplicateFields()
{
var recordField = new Field(PrimitiveSchema.Create(Schema.Type.Long),
"value",
new List<string> { "oldName" },
0,
null,
"100",
Field.SortOrder.ignore,
null);
Assert.Throws<AvroException>(() => RecordSchema.Create("Longs",
new List<Field>
{
recordField,
recordField
}));
}
[TestCase]
public void TestRecordFieldNames() {
var fields = new List<Field>
{
new Field(PrimitiveSchema.Create(Schema.Type.Long),
"歳以上",
null,
0,
null,
null,
Field.SortOrder.ignore,
null)
};
var recordSchema = RecordSchema.Create("LongList", fields, null, new[] { "LinkedLongs" });
Field f = recordSchema.Fields[0];
Assert.AreEqual("歳以上", f.Name);
}
[TestCase]
public void TestRecordCreationWithRecursiveRecord()
{
string schema = "{\"type\":\"record\",\"name\":\"LongList\",\"aliases\":[\"LinkedLongs\"],\"fields\":[{\"name\":\"value\",\"type\":\"long\"},{\"name\":\"next\",\"type\":[\"null\",\"LongList\"]}]}";
var recordSchema = RecordSchema.Create("LongList", new List<Field>(), null, new[] { "LinkedLongs" });
recordSchema.Fields = new List<Field>
{
new Field(PrimitiveSchema.Create(Schema.Type.Long),
"value",
null,
0,
null,
null,
Field.SortOrder.ignore,
null),
new Field(UnionSchema.Create(
new List<Schema>
{
PrimitiveSchema.Create(Schema.Type.Null), recordSchema
}),
"next",
1)
};
Assert.AreEqual(schema, recordSchema.ToString());
}
[TestCase("{\"type\":\"enum\",\"name\":\"Test\",\"symbols\":[\"A\",\"B\"]}",
new string[] { "A", "B" })]
[TestCase("{\"type\":\"enum\",\"name\":\"Test\",\"symbols\":[\"A\",\"B\"]}",
new string[] { "A", "B" })]
[TestCase("{\"type\":\"enum\",\"name\":\"Test\",\"doc\":\"Some explanation\",\"namespace\":\"mynamespace\",\"aliases\":[\"mynamespace.Alias\"],\"symbols\":[\"UNKNOWN\",\"A\",\"B\"],\"default\":\"UNKNOWN\",\"propertyKey\":\"propertyValue\"}",
new string[] { "UNKNOWN", "A", "B" }, "mynamespace", new string[] { "Alias" }, "Some explanation", true, "UNKNOWN")]
[TestCase("{\"type\":\"enum\",\"name\":\"Test\",\"doc\":\"Some explanation\",\"namespace\":\"space\",\"aliases\":[\"internalNamespace.Alias\"],\"symbols\":[\"UNKNOWN\",\"A\",\"B\"]}",
new string[] { "UNKNOWN", "A", "B" }, "space", new string[] { "internalNamespace.Alias" }, "Some explanation")]
[TestCase("{\"type\":\"enum\",\"name\":\"Test\",\"doc\":\"Some explanation\",\"namespace\":\"space\",\"aliases\":[\"internalNamespace.Alias\"],\"symbols\":[]}",
new string[] { }, "space", new string[] { "internalNamespace.Alias" }, "Some explanation")]
public void TestEnum(string s, string[] symbols, string space = null, IEnumerable<string> aliases = null, string doc = null, bool? usePropertyMap = null, string defaultSymbol = null)
{
Schema sc = Schema.Parse(s);
PropertyMap propertyMap = new PropertyMap();
propertyMap.Add("propertyKey", "\"propertyValue\"");
Schema schema = EnumSchema.Create("Test",
symbols,
space,
aliases,
usePropertyMap == true ? propertyMap : null,
doc,
defaultSymbol);
Assert.AreEqual(sc, schema);
Assert.AreEqual(s, schema.ToString());
Assert.AreEqual(Schema.Type.Enumeration, sc.Tag);
EnumSchema es = sc as EnumSchema;
Assert.AreEqual(symbols.Length, es.Count);
int i = 0;
foreach (string str in es)
{
Assert.AreEqual(symbols[i++], str);
}
testEquality(s, sc);
testToString(sc, s);
}
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}", null)]
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"], \"doc\": \"\"}", "")]
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"], \"doc\": \"this is a test\"}", "this is a test")]
public void TestEnumDoc(string s, string expectedDoc)
{
var es = Schema.Parse(s) as EnumSchema;
Assert.IsNotNull(es);
Assert.AreEqual(expectedDoc, es.Documentation);
}
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"Unknown\", \"A\", \"B\"], \"default\": \"Unknown\" }", "Unknown")]
public void TestEnumDefault(string s, string expectedToken)
{
var es = Schema.Parse(s) as EnumSchema;
Assert.IsNotNull(es);
Assert.AreEqual(es.Default, expectedToken);
}
[TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"Unknown\", \"A\", \"B\"], \"default\": \"Something\" }")]
public void TestEnumDefaultSymbolDoesntExist(string s)
{
Assert.Throws<SchemaParseException>(() => Schema.Parse(s));
}
[TestCase("name", new string[] { "A", "B" }, "s", new[] { "L1", "L2" }, "regular enum", null, "name", "s")]
[TestCase("s.name", new string[] { "A", "B" }, null, new[] { "L1", "L2" }, "internal namespace", null, "name", "s")]
[TestCase("name", new string[] { "A", "B" }, null, new[] { "L1", "L2" }, "no namespace", null, "name", null)]
[TestCase("name", new string[] { "A", "B" }, null, new[] { "L1", "L2" }, "with default value", "A", "name", null)]
[TestCase("name", new string[] { "A1B2", "B4324" }, null, new[] { "L1", "L2" }, "with longer symbols", "B4324", "name", null)]
[TestCase("name", new string[] { "_A1B2_", "B4324" }, null, new[] { "L1", "L2" }, "underscore in symbols", "_A1B2_", "name", null)]
public void TestEnumCreation(string name, string[] symbols, string space, string[] aliases, string doc, string defaultSymbol, string expectedName, string expectedNamespace)
{
EnumSchema enumSchema = EnumSchema.Create(name, symbols, space, aliases, null, doc, defaultSymbol);
Assert.AreEqual(expectedName, enumSchema.Name);
CollectionAssert.AreEqual(symbols, enumSchema.Symbols);
Assert.AreEqual(expectedNamespace, enumSchema.Namespace);
Assert.AreEqual(Schema.Type.Enumeration, enumSchema.Tag);
Assert.AreEqual(doc, enumSchema.Documentation);
Assert.AreEqual(defaultSymbol, enumSchema.Default);
}
[TestCase(new[] {"A", "B"}, "C")]
[TestCase(new[] {null, "B"}, null)]
[TestCase(new[] {"", "B" }, null)]
[TestCase(new[] {"8", "B" }, null)]
[TestCase(new[] {"8", "B" }, null)]
[TestCase(new[] {"A", "A" }, null)]
[TestCase(new[] {" ", "A" }, null)]
[TestCase(new[] {"9A23", "A" }, null)]
public void TestEnumInvalidSymbols(string[] symbols, string defaultSymbol)
{
Assert.Throws<AvroException>(() => EnumSchema.Create("name", symbols, defaultSymbol: defaultSymbol));
}
[TestCase("{\"type\": \"array\", \"items\": \"long\"}", "long")]
public void TestArray(string s, string item)
{
Schema sc = Schema.Parse(s);
Assert.AreEqual(Schema.Type.Array, sc.Tag);
ArraySchema ars = (ArraySchema)sc;
Assert.AreEqual(item, ars.ItemSchema.Name);
testEquality(s, sc);
testToString(sc);
}
[TestCase]
public void TestArrayCreation()
{
PrimitiveSchema itemsSchema = PrimitiveSchema.Create(Schema.Type.String);
ArraySchema arraySchema = ArraySchema.Create(itemsSchema);
Assert.AreEqual("array", arraySchema.Name);
Assert.AreEqual(Schema.Type.Array, arraySchema.Tag);
Assert.AreEqual(itemsSchema, arraySchema.ItemSchema);
}
[TestCase]
public void TestInvalidArrayCreation()
{
Assert.Throws<ArgumentNullException>(() => ArraySchema.Create(null));
}
[TestCase("{\"type\": \"int\", \"logicalType\": \"date\"}", "int", "date")]
public void TestLogicalPrimitive(string s, string baseType, string logicalType)
{
Schema sc = Schema.Parse(s);
Assert.AreEqual(Schema.Type.Logical, sc.Tag);
LogicalSchema logsc = sc as LogicalSchema;
Assert.AreEqual(baseType, logsc.BaseSchema.Name);
Assert.AreEqual(logicalType, logsc.LogicalType.Name);
testEquality(s, sc);
testToString(sc);
}
[TestCase("{\"type\": \"int\", \"logicalType\": \"unknown\"}", "unknown")]
public void TestUnknownLogical(string s, string unknownType)
{
var err = Assert.Throws<AvroTypeException>(() => Schema.Parse(s));
Assert.AreEqual("Logical type '" + unknownType + "' is not supported.", err.Message);
}
[TestCase("{\"type\": \"map\", \"values\": \"long\"}", "long")]
public void TestMap(string s, string value)
{
Schema sc = Schema.Parse(s);
Assert.AreEqual(Schema.Type.Map, sc.Tag);
MapSchema ms = (MapSchema)sc;
Assert.AreEqual(value, ms.ValueSchema.Name);
testEquality(s, sc);
testToString(sc);
}
[TestCase]
public void TestMapCreation()
{
PrimitiveSchema mapType = PrimitiveSchema.Create(Schema.Type.Float);
MapSchema mapSchema = MapSchema.CreateMap(mapType);
Assert.AreEqual("map", mapSchema.Fullname);
Assert.AreEqual("map", mapSchema.Name);
Assert.AreEqual(Schema.Type.Map, mapSchema.Tag);
Assert.AreEqual(mapType, mapSchema.ValueSchema);
}
[TestCase]
public void TestInvalidMapCreation()
{
Assert.Throws<ArgumentNullException>(() => MapSchema.CreateMap(null));
}
[TestCase("[\"string\", \"null\", \"long\"]",
new Schema.Type[] { Schema.Type.String, Schema.Type.Null, Schema.Type.Long })]
public void TestUnion(string s, Schema.Type[] types)
{
Schema sc = Schema.Parse(s);
UnionSchema schema = UnionSchema.Create(types.Select(t => (Schema)PrimitiveSchema.Create(t)).ToList());
Assert.AreEqual(sc, schema);
Assert.AreEqual(Schema.Type.Union, sc.Tag);
UnionSchema us = (UnionSchema)sc;
Assert.AreEqual(types.Length, us.Count);
for (int i = 0; i < us.Count; i++)
{
Assert.AreEqual(types[i].ToString().ToLower(), us[i].Name);
}
testEquality(s, sc);
testToString(sc);
}
[TestCase]
public void TestUnionCreation()
{
UnionSchema unionSchema = UnionSchema.Create(new List<Schema> { PrimitiveSchema.Create(Schema.Type.Null), PrimitiveSchema.Create(Schema.Type.String) });
CollectionAssert.AreEqual(new List<Schema> { PrimitiveSchema.Create(Schema.Type.Null), PrimitiveSchema.Create(Schema.Type.String) },
unionSchema.Schemas);
}
[TestCase]
public void TestUnionCreationWithDuplicateSchemas()
{
Assert.Throws<ArgumentException>(() => UnionSchema.Create(new List<Schema> { PrimitiveSchema.Create(Schema.Type.String), PrimitiveSchema.Create(Schema.Type.String) }));
}
[TestCase]
public void TestUnionNestedUnionCreation()
{
Assert.Throws<ArgumentException>(() => UnionSchema.Create(new List<Schema> { UnionSchema.Create(new List<Schema>()), PrimitiveSchema.Create(Schema.Type.String) }));
}
[TestCase("{\"type\":\"fixed\",\"name\":\"Test\",\"size\":1}", 1)]
public void TestFixed(string s, int size)
{
Schema sc = Schema.Parse(s);
FixedSchema schema = FixedSchema.Create("Test", 1);
Assert.AreEqual(sc, schema);
Assert.AreEqual(s, schema.ToString());
Assert.AreEqual(Schema.Type.Fixed, sc.Tag);
FixedSchema fs = sc as FixedSchema;
Assert.AreEqual(size, fs.Size);
testEquality(s, sc);
testToString(sc);
}
[TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}", null)]
[TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1, \"doc\": \"\"}", "")]
[TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1, \"doc\": \"this is a test\"}", "this is a test")]
public void TestFixedDoc(string s, string expectedDoc)
{
var fs = Schema.Parse(s) as FixedSchema;
Assert.IsNotNull(fs);
Assert.AreEqual(expectedDoc, fs.Documentation);
}
[TestCase]
public void TestFixedCreation()
{
string s = @"{""type"":""fixed"",""name"":""fixedName"",""namespace"":""space"",""aliases"":[""space.fixedOldName""],""size"":10}";
FixedSchema fixedSchema = FixedSchema.Create("fixedName", 10, "space", new[] { "fixedOldName" }, null);
Assert.AreEqual("fixedName", fixedSchema.Name);
Assert.AreEqual("space.fixedName", fixedSchema.Fullname);
Assert.AreEqual(10, fixedSchema.Size);
Assert.AreEqual(s, fixedSchema.ToString());
}
[TestCase("a", "o.a.h", ExpectedResult = "o.a.h.a")]
public string testFullname(string s1, string s2)
{
var name = new SchemaName(s1, s2, null, null);
return name.Fullname;
}
[TestCase("{ \"type\": \"int\" }", "int")]
[SetCulture("tr-TR")]
public void TestSchemaNameInTurkishCulture(string schemaJson, string expectedName)
{
var schema = Schema.Parse(schemaJson);
Assert.AreEqual(expectedName, schema.Name);
}
[TestCase("[\"null\",\"string\"]", "[\"null\",\"string\"]")]
public void TestUnionSchemaWithoutTypeProperty(string schemaJson, string expectedSchemaJson)
{
var schema = Schema.Parse(schemaJson);
Assert.AreEqual(schema.ToString(), expectedSchemaJson);
}
[TestFixture]
public class SchemaTypeExtensionsTests
{
[TestCase("null", Schema.Type.Null)]
[TestCase("boolean", Schema.Type.Boolean)]
[TestCase("int", Schema.Type.Int)]
[TestCase("long", Schema.Type.Long)]
[TestCase("float", Schema.Type.Float)]
[TestCase("double", Schema.Type.Double)]
[TestCase("bytes", Schema.Type.Bytes)]
[TestCase("string", Schema.Type.String)]
[TestCase("record", Schema.Type.Record)]
[TestCase("enumeration", Schema.Type.Enumeration)]
[TestCase("array", Schema.Type.Array)]
[TestCase("map", Schema.Type.Map)]
[TestCase("union", Schema.Type.Union)]
[TestCase("fixed", Schema.Type.Fixed)]
[TestCase("error", Schema.Type.Error)]
[TestCase("logical", Schema.Type.Logical)]
[TestCase("Logical", null)]
[TestCase("InvalidValue", null)]
[TestCase("\"null\"", null)]
[TestCase("", null)]
[TestCase(null, null)]
public void ParseTypeTest(string value, object expectedResult)
{
Assert.AreEqual(Schema.ParseType(value), expectedResult);
}
[TestCase("\"null\"", Schema.Type.Null)]
[TestCase("\"nu\"ll\"", null)]
[TestCase("\"\"", null)]
public void ParseTypeRemoveQuotesTest(string value, object expectedResult)
{
Assert.AreEqual(Schema.ParseType(value, true), expectedResult);
}
}
}
}