blob: cce3bb4ff26dc29289f3c93e9c8351bf67166d28 [file]
/*
* 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.Linq;
using Apache.IoTDB.DataStructure;
using NUnit.Framework;
namespace Apache.IoTDB.Tests
{
[TestFixture]
public class RpcDataSetTests
{
/// <summary>
/// Builds a serialized TsBlock with 2 rows and 3 value columns (INT32, BOOLEAN, DOUBLE).
/// Row 0: time=1000, int32=42, boolean=null, double=3.14
/// Row 1: time=2000, int32=null, boolean=true, double=null
/// </summary>
private static byte[] BuildTestTsBlockBytes()
{
var buf = new ByteBuffer(256);
// 1. value column count
buf.AddInt(3);
// 2. value column data types: INT32(1), BOOLEAN(0), DOUBLE(4)
buf.AddByte((byte)TSDataType.INT32);
buf.AddByte((byte)TSDataType.BOOLEAN);
buf.AddByte((byte)TSDataType.DOUBLE);
// 3. position count
buf.AddInt(2);
// 4. column encodings: time=Int64Array(2), int32=Int32Array(1), boolean=ByteArray(0), double=Int64Array(2)
buf.AddByte((byte)ColumnEncoding.Int64Array);
buf.AddByte((byte)ColumnEncoding.Int32Array);
buf.AddByte((byte)ColumnEncoding.ByteArray);
buf.AddByte((byte)ColumnEncoding.Int64Array);
// 5. Time column (Int64Array): no nulls, 2 values
buf.AddByte(0); // mayHaveNull = false
buf.AddLong(1000L);
buf.AddLong(2000L);
// 6. INT32 column (Int32Array): row1 is null
buf.AddByte(1); // mayHaveNull = true
// null indicators packed: [false, true] → bit7=0, bit6=1 → 0x40
buf.AddByte(0x40);
// only non-null value (row 0)
buf.AddInt(42);
// 7. BOOLEAN column (ByteArray): row0 is null
buf.AddByte(1); // mayHaveNull = true
// null indicators packed: [true, false] → bit7=1, bit6=0 → 0x80
buf.AddByte(0x80);
// boolean values packed (all positions): [false, true] → bit7=0, bit6=1 → 0x40
buf.AddByte(0x40);
// 8. DOUBLE column (Int64Array): row1 is null
buf.AddByte(1); // mayHaveNull = true
// null indicators packed: [false, true] → 0x40
buf.AddByte(0x40);
// only non-null value (row 0)
buf.AddDouble(3.14);
return buf.GetBuffer();
}
private RpcDataSet CreateTestDataSet(List<byte[]> queryResult = null)
{
var columnNames = new List<string> { "s_int32", "s_boolean", "s_double" };
var columnTypes = new List<string> { "INT32", "BOOLEAN", "DOUBLE" };
var columnNameIndex = new Dictionary<string, int>
{
{ "s_int32", 0 },
{ "s_boolean", 1 },
{ "s_double", 2 }
};
var columnIndex2TsBlockColumnIndexList = new List<int> { 0, 1, 2 };
queryResult ??= new List<byte[]> { BuildTestTsBlockBytes() };
return new RpcDataSet(
sql: "SELECT * FROM root.test",
columnNameList: columnNames,
columnTypeList: columnTypes,
columnNameIndex: columnNameIndex,
ignoreTimestamp: false,
moreData: false,
queryId: 1,
statementId: 1,
client: null,
sessionId: 1,
queryResult: queryResult,
fetchSize: 1024,
timeout: 10000,
zoneId: "UTC",
columnIndex2TsBlockColumnIndexList: columnIndex2TsBlockColumnIndexList
);
}
[Test]
public void CurrentBatchRowCount_ReturnsCorrectSize_BeforeFirstNext()
{
var dataSet = CreateTestDataSet();
Assert.That(dataSet._tsBlockSize, Is.EqualTo(2),
"CurrentBatchRowCount should return the TsBlock row count immediately after construction.");
}
[Test]
public void CurrentBatchRowCount_ReturnsZero_WhenNoData()
{
var dataSet = CreateTestDataSet(queryResult: new List<byte[]>());
Assert.That(dataSet._tsBlockSize, Is.EqualTo(0),
"CurrentBatchRowCount should return 0 when no query results are provided.");
}
[Test]
public void GetRow_ExcludesNullValuedMeasurements_ForValueTypes()
{
var dataSet = CreateTestDataSet();
// Advance to row 0: int32=42, boolean=null, double=3.14
dataSet.Next();
var row0 = dataSet.GetRow();
Assert.That(row0.Timestamps, Is.EqualTo(1000L));
Assert.That(row0.Measurements, Does.Contain("s_int32"));
Assert.That(row0.Measurements, Does.Not.Contain("s_boolean"),
"Null BOOLEAN measurement should be excluded from row.");
Assert.That(row0.Measurements, Does.Contain("s_double"));
Assert.That(row0.Values.Count, Is.EqualTo(2), "Row 0 should have 2 non-null values.");
}
[Test]
public void GetRow_ExcludesNullValuedMeasurements_ForInt32AndDouble()
{
var dataSet = CreateTestDataSet();
// Advance to row 0 then row 1
dataSet.Next();
dataSet.Next();
var row1 = dataSet.GetRow();
Assert.That(row1.Timestamps, Is.EqualTo(2000L));
Assert.That(row1.Measurements, Does.Not.Contain("s_int32"),
"Null INT32 measurement should be excluded from row.");
Assert.That(row1.Measurements, Does.Contain("s_boolean"));
Assert.That(row1.Measurements, Does.Not.Contain("s_double"),
"Null DOUBLE measurement should be excluded from row.");
Assert.That(row1.Values.Count, Is.EqualTo(1), "Row 1 should have 1 non-null value.");
Assert.That(row1.Values[0], Is.EqualTo(true));
}
[Test]
public void GetRow_DataTypesMatchMeasurements()
{
var dataSet = CreateTestDataSet();
dataSet.Next();
var row0 = dataSet.GetRow();
Assert.That(row0.DataTypes.Count, Is.EqualTo(row0.Measurements.Count),
"DataTypes count should match Measurements count.");
Assert.That(row0.DataTypes.Count, Is.EqualTo(row0.Values.Count),
"DataTypes count should match Values count.");
}
}
}