blob: 3b55387b1dd9f2ae0d2291622043d0dded0e764a [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
*
* http://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 System.IO;
using System.Linq;
using System.Reflection;
using Apache.Arrow.Ipc;
using Xunit;
namespace Apache.Arrow.Adbc.Tests
{
/// <summary>
/// Validate the support for adbc.h for the current version
/// of ADBC found in the build project.
/// </summary>
public class AdbcTests
{
[Theory]
[InlineData(AdbcStatusCode.Success, "ADBC_STATUS_OK", 0)]
[InlineData(AdbcStatusCode.UnknownError, "ADBC_STATUS_UNKNOWN", 1)]
[InlineData(AdbcStatusCode.NotImplemented, "ADBC_STATUS_NOT_IMPLEMENTED", 2)]
[InlineData(AdbcStatusCode.NotFound, "ADBC_STATUS_NOT_FOUND", 3)]
[InlineData(AdbcStatusCode.AlreadyExists, "ADBC_STATUS_ALREADY_EXISTS", 4)]
[InlineData(AdbcStatusCode.InvalidArgument, "ADBC_STATUS_INVALID_ARGUMENT", 5)]
[InlineData(AdbcStatusCode.InvalidState, "ADBC_STATUS_INVALID_STATE", 6)]
[InlineData(AdbcStatusCode.InvalidData, "ADBC_STATUS_INVALID_DATA", 7)]
[InlineData(AdbcStatusCode.IntegrityError, "ADBC_STATUS_INTEGRITY", 8)]
[InlineData(AdbcStatusCode.InternalError, "ADBC_STATUS_INTERNAL", 9)]
[InlineData(AdbcStatusCode.IOError, "ADBC_STATUS_IO", 10)]
[InlineData(AdbcStatusCode.Cancelled, "ADBC_STATUS_CANCELLED", 11)]
[InlineData(AdbcStatusCode.Timeout, "ADBC_STATUS_TIMEOUT", 12)]
[InlineData(AdbcStatusCode.Unauthenticated, "ADBC_STATUS_UNAUTHENTICATED", 13)]
[InlineData(AdbcStatusCode.Unauthorized, "ADBC_STATUS_UNAUTHORIZED", 14)]
public void ValidateStatusCodes(AdbcStatusCode code, string adbcName, int value)
{
ValidateEnumValue((int)code, adbcName, value);
}
[Theory]
[InlineData(AdbcInfoCode.VendorName, "ADBC_INFO_VENDOR_NAME", 0)]
[InlineData(AdbcInfoCode.VendorVersion, "ADBC_INFO_VENDOR_VERSION", 1)]
[InlineData(AdbcInfoCode.VendorArrowVersion, "ADBC_INFO_VENDOR_ARROW_VERSION", 2)]
[InlineData(AdbcInfoCode.DriverName, "ADBC_INFO_DRIVER_NAME", 100)]
[InlineData(AdbcInfoCode.DriverVersion, "ADBC_INFO_DRIVER_VERSION", 101)]
[InlineData(AdbcInfoCode.DriverArrowVersion, "ADBC_INFO_DRIVER_ARROW_VERSION", 102)]
public void ValidateInfoCodes(AdbcInfoCode code, string adbcName, int value)
{
ValidateEnumValue((int)code, adbcName, value);
}
/// <summary>
/// Validates that a defined enum value matches the corresponding value in `adbc.h`.
/// </summary>
/// <param name="enumValue">The enum value.</param>
/// <param name="adbcName">The name of the ADBC value.</param>
/// <param name="value">The value of the ADBC value.</param>
private void ValidateEnumValue(int enumValue, string adbcName, int value)
{
Assert.Equal(enumValue, value);
// find the corresponding value in adbc.h and validate it
string path = GetPathForAdbcH();
string pattern = "#define " + adbcName;
string? line = File.ReadAllLines(path).Where(x => x.StartsWith(pattern)).FirstOrDefault();
Assert.False(string.IsNullOrEmpty(line));
string definedValue = line.Replace(pattern, "").Trim();
Assert.Equal(value, Convert.ToInt32(definedValue));
}
// C# is designed to match Java's AdbcDriver
[Theory]
[InlineData("Open", new string[] { "parameters" }, new Type[] { typeof(IReadOnlyDictionary<string, string>) })]
public void ValidateAdbcDriverMethods(string name, string[]? parameterNames = null, Type[]? parameterTypes = null)
{
ValidateMethod(typeof(AdbcDriver), name, parameterNames, parameterTypes);
}
// C# is designed to match Java's AdbcDatabase
[Theory]
[InlineData("Connect", new string[] { "options" }, new Type[] { typeof(IReadOnlyDictionary<string, string>) })]
public void ValidateAdbcDatabaseMethods(string name, string[]? parameterNames = null, Type[]? parameterTypes = null)
{
ValidateMethod(typeof(AdbcDatabase), name, parameterNames, parameterTypes);
}
[Theory]
[InlineData("Commit")]
[InlineData("CreateStatement")]
[InlineData("GetInfo", new string[] { "codes" }, new Type[] { typeof(IReadOnlyList<AdbcInfoCode>) })]
[InlineData("GetObjects",
new string[] { "depth", "catalogPattern", "dbSchemaPattern", "tableNamePattern", "tableTypes", "columnNamePattern" },
new Type[] { typeof(AdbcConnection.GetObjectsDepth), typeof(string), typeof(string), typeof(string), typeof(IReadOnlyList<string>), typeof(string) })]
[InlineData("GetTableSchema",
new string[] { "catalog", "dbSchema", "tableName" },
new Type[] { typeof(string), typeof(string), typeof(string) })]
[InlineData("GetTableTypes")]
[InlineData("ReadPartition", new string[] { "partition" }, new Type[] { typeof(PartitionDescriptor) })]
[InlineData("Rollback")]
[InlineData("SetOption", new string[] { "key", "value" }, new Type[] { typeof(string), typeof(string) })]
public void ValidateAdbcConnectionMethods(string name, string[]? parameterNames = null, Type[]? parameterTypes = null)
{
ValidateMethod(typeof(AdbcConnection), name, parameterNames, parameterTypes);
}
[Theory]
[InlineData("IsolationLevel", typeof(IsolationLevel))]
[InlineData("ReadOnly", typeof(bool))]
public void ValidateAdbcConnectionProperties(string name, Type type)
{
ValidateProperty(typeof(AdbcConnection), name, type);
}
[Theory]
// TODO: Bind is defined differently to take a batch rather than an array
[InlineData("Bind", new string[] { "batch", "schema" }, new Type[] { typeof(RecordBatch), typeof(Schema) })]
[InlineData("BindStream", new string[] { "stream" }, new Type[] { typeof(IArrowArrayStream) })]
[InlineData("ExecuteQuery")]
[InlineData("ExecuteUpdate")]
[InlineData("ExecutePartitioned")] // C# matches Java here
[InlineData("GetParameterSchema")]
[InlineData("Prepare")]
[InlineData("SetOption", new string[] { "key", "value" }, new Type[] { typeof(string), typeof(string) })]
public void ValidateAdbcStatementMethods(string name, string[]? parameterNames = null, Type[]? parameterTypes = null)
{
ValidateMethod(typeof(AdbcStatement), name, parameterNames, parameterTypes);
}
[Theory]
[InlineData("SqlQuery", typeof(string))]
[InlineData("SubstraitPlan", typeof(byte[]))]
public void ValidateAdbcAdbcStatementProperties(string name, Type type)
{
ValidateProperty(typeof(AdbcStatement), name, type);
}
/// <summary>
/// Validate the methods of the type (in accordance to the adbc.h file)
/// </summary>
/// <param name="t">The type to verify</param>
/// <param name="methodName">The name of the method</param>
/// <param name="parameterNames">The parameter names (in order)</param>
/// <param name="parameterTypes">The parameter types (in order)</param>
private void ValidateMethod(Type t, string methodName, string[]? parameterNames = null, Type[]? parameterTypes = null)
{
MethodInfo? mi;
if (parameterTypes != null)
mi = t.GetMethod(methodName, parameterTypes);
else
mi = t.GetMethod(methodName);
if (parameterNames != null)
{
Assert.NotNull(mi);
Assert.True(parameterNames.Length > 0);
Assert.True(parameterTypes != null);
Assert.Equal(parameterNames.Length, parameterTypes.Length);
ParameterInfo[] parameters = mi.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
ParameterInfo parameter = parameters[i];
Assert.Equal(parameter.Name, parameterNames[i]);
Assert.Equal(parameter.ParameterType, parameterTypes[i]);
}
}
}
/// <summary>
/// Validate the methods of the type (in accordance to the adbc.h file)
/// </summary>
/// <param name="t">The type to verify</param>
/// <param name="methodName">The name of the method</param>
/// <param name="parameterNames">The parameter names (in order)</param>
/// <param name="parameterTypes">The parameter types (in order)</param>
private void ValidateProperty(Type t, string propertyName, Type propertyType)
{
PropertyInfo? pi = t.GetProperty(propertyName, propertyType);
Assert.NotNull(pi);
}
private string GetPathForAdbcH()
{
// find the adbc.h file from the repo
string path = Path.Combine(new string[] { "..", "..", "..", "..", "..", "c", "include", "arrow-adbc", "adbc.h"});
Assert.True(File.Exists(path));
return path;
}
}
}