This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch gg-20650
in repository https://gitbox.apache.org/repos/asf/ignite-3.git

commit 1288724cf9e4749f09cb55ea4f8613a35831b7cd
Author: amashenkov <[email protected]>
AuthorDate: Thu May 30 15:07:20 2024 +0300

    Tuple tests refactoring.
---
 .../main/java/org/apache/ignite/table/Tuple.java   |   3 +-
 .../java/org/apache/ignite/table/TupleImpl.java    |   3 +-
 .../ignite/internal/table/ItColumnMappingTest.java | 180 ++++++++
 .../schema/marshaller/TupleMarshallerImpl.java     |   3 +-
 .../apache/ignite/table/AbstractTupleSelfTest.java | 456 +++++++++++++++++++++
 .../org/apache/ignite/table/TupleImplTest.java     | 275 +------------
 6 files changed, 647 insertions(+), 273 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/table/Tuple.java 
b/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
index 4526f9335b..545b4c47bb 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/Tuple.java
@@ -155,7 +155,8 @@ public interface Tuple extends Iterable<Object> {
         }
 
         for (int idx = 0; idx < columns; idx++) {
-            int idx2 = secondTuple.columnIndex(firstTuple.columnName(idx));
+            // fix this hack
+            int idx2 = secondTuple.columnIndex("\""+ 
firstTuple.columnName(idx) +"\"");
 
             if (idx2 < 0) {
                 return false;
diff --git a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java 
b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
index 998afb2b51..6c7fd8ee9c 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
@@ -78,7 +78,8 @@ class TupleImpl implements Tuple, Serializable {
         this(tuple.columnCount());
 
         for (int i = 0, len = tuple.columnCount(); i < len; i++) {
-            set(tuple.columnName(i), tuple.value(i));
+            // fix this hack
+            set("\"" + tuple.columnName(i) + "\"", tuple.value(i));
         }
     }
 
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItColumnMappingTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItColumnMappingTest.java
new file mode 100644
index 0000000000..6f0080f449
--- /dev/null
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItColumnMappingTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.table;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import javax.annotation.Nullable;
+import org.apache.ignite.internal.ClusterPerClassIntegrationTest;
+import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.lang.MarshallerException;
+import org.apache.ignite.table.KeyValueView;
+import org.apache.ignite.table.RecordView;
+import org.apache.ignite.table.Table;
+import org.apache.ignite.table.Tuple;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+public class ItColumnMappingTest extends ClusterPerClassIntegrationTest {
+    @AfterEach
+    public void dropTables() {
+        for (Table t : CLUSTER.aliveNode().tables().tables()) {
+            sql("DROP TABLE " + t.name());
+        }
+    }
+
+    @Test
+    public void accessUnquotedColumnViaKvView() {
+        sql("CREATE TABLE test ("
+                + "id BIGINT PRIMARY KEY, "
+                + "ColumnName INT"
+                + ")");
+
+        IgniteImpl node = CLUSTER.aliveNode();
+        Table table = node.tables().table("test");
+
+        KeyValueView<Tuple, Tuple> view = table.keyValueView();
+
+        view.put(null, Tuple.create().set("id", 1L), 
Tuple.create().set("columnname", 1));
+        view.put(null, Tuple.create().set("id", 2L), 
Tuple.create().set("COLUMNNAME", 2));
+        view.put(null, Tuple.create().set("id", 3L), 
Tuple.create().set("ColumnName", 3));
+
+        checkUnquotedColumn(1, view.get(null, Tuple.create().set("id", 1L)));
+        checkUnquotedColumn(2, view.get(null, Tuple.create().set("id", 2L)));
+        checkUnquotedColumn(3, view.get(null, Tuple.create().set("id", 3L)));
+
+        view.put(null, Tuple.create().set("id", 4L), 
Tuple.create().set("\"COLUMNNAME\"", 4));
+        checkUnquotedColumn(4, view.get(null, Tuple.create().set("id", 4L)));
+
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 5L), 
Tuple.create().set("\"columnname\"", 5)));
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 6L), 
Tuple.create().set("\"columnName\"", 6)));
+    }
+
+    @Disabled
+    @Test
+    public void accessUnquotedColumnViaRecordView() {
+        sql("CREATE TABLE test ("
+                + "id BIGINT PRIMARY KEY, "
+                + "ColumnName INT"
+                + ")");
+
+        IgniteImpl node = CLUSTER.aliveNode();
+        Table table = node.tables().table("test");
+
+        RecordView<Tuple> view = table.recordView();
+
+        view.insert(null, Tuple.create().set("id", 1L).set("columnname", 1));
+        view.insert(null, Tuple.create().set("id", 2L).set("COLUMNAME", 2));
+        view.insert(null, Tuple.create().set("id", 3L).set("ColumnName", 3));
+
+        checkUnquotedColumn(1, view.get(null, Tuple.create().set("id", 1L)));
+        checkUnquotedColumn(2, view.get(null, Tuple.create().set("id", 2L)));
+        checkUnquotedColumn(3, view.get(null, Tuple.create().set("id", 3L)));
+
+        view.insert(null, Tuple.create().set("id", 4L).set("\"columnname\"", 
4));
+        view.insert(null, Tuple.create().set("id", 5L).set("\"ColumnName\"", 
5));
+        view.insert(null, Tuple.create().set("id", 6L).set("\"COLUMNAME\"", 
6));
+
+        checkUnquotedColumn(null, view.get(null, Tuple.create().set("id", 
4L)));
+        checkUnquotedColumn(null, view.get(null, Tuple.create().set("id", 
5L)));
+        checkUnquotedColumn(6, view.get(null, Tuple.create().set("id", 6L)));
+    }
+
+    @Test
+    public void accessQuotedColumnViaKvView() {
+        sql("CREATE TABLE test ("
+                + "id BIGINT PRIMARY KEY, "
+                + "\"ColumnName\" INT"
+                + ")");
+
+        IgniteImpl node = CLUSTER.aliveNode();
+        Table table = node.tables().table("test");
+
+        KeyValueView<Tuple, Tuple> view = table.keyValueView();
+
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 1L), 
Tuple.create().set("columnname", 1)));
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 2L), 
Tuple.create().set("COLUMNNAME", 2)));
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 3L), 
Tuple.create().set("ColumnName", 3)));
+
+        assertNull(view.get(null, Tuple.create().set("id", 1L)));
+        assertNull(view.get(null, Tuple.create().set("id", 2L)));
+        assertNull(view.get(null, Tuple.create().set("id", 3L)));
+
+        view.put(null, Tuple.create().set("id", 4L), 
Tuple.create().set("\"ColumnName\"", 4));
+
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 5L), 
Tuple.create().set("\"columnname\"", 5)));
+        assertThrows(MarshallerException.class, () ->
+                view.put(null, Tuple.create().set("id", 6L), 
Tuple.create().set("\"COLUMNNAME\"", 6)));
+
+        checkQuotedColumn(4, view.get(null, Tuple.create().set("id", 4L)));
+        assertNull(view.get(null, Tuple.create().set("id", 5L)));
+        assertNull(view.get(null, Tuple.create().set("id", 6L)));
+    }
+
+    private static void checkQuotedColumn(@Nullable Object expectedValue, 
@Nullable Tuple tuple) {
+        assertNotNull(tuple);
+
+        assertNull(tuple.valueOrDefault("columnname", null));
+        assertNull(tuple.valueOrDefault("COLUMNNAME", null));
+        assertNull(tuple.valueOrDefault("ColumnName", null));
+
+        assertNull(tuple.valueOrDefault("\"columnname\"", null));
+        assertNull(tuple.valueOrDefault("\"COLUMNNAME\"", null));
+        assertEquals(expectedValue, tuple.valueOrDefault("\"ColumnName\"", 
null));
+    }
+
+    private static void checkUnquotedColumn(@Nullable Object expectedValue, 
@Nullable Tuple tuple) {
+        assertNotNull(tuple);
+
+        assertEquals(expectedValue, tuple.valueOrDefault("columnname", null));
+        assertEquals(expectedValue, tuple.valueOrDefault("COLUMNNAME", null));
+        assertEquals(expectedValue, tuple.valueOrDefault("ColumnName", null));
+        ;
+
+        assertNull(tuple.valueOrDefault("\"columnname\"", null));
+        assertEquals(expectedValue, tuple.valueOrDefault("\"COLUMNNAME\"", 
null));
+        assertNull(tuple.valueOrDefault("\"ColumnName\"", null));
+    }
+}
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
index 36b9b25e74..02a84b3181 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
@@ -174,7 +174,8 @@ public class TupleMarshallerImpl implements TupleMarshaller 
{
         for (Column col : columns) {
             NativeType colType = col.type();
 
-            Object val = tuple.valueOrDefault(col.name(), POISON_OBJECT);
+            // fix this hack
+            Object val = tuple.valueOrDefault("\"" + col.name() + "\"", 
POISON_OBJECT);
 
             if (val == POISON_OBJECT && col.positionInKey() != -1) {
                 throw new SchemaMismatchException("Missed key column: " + 
col.name());
diff --git 
a/modules/table/src/test/java/org/apache/ignite/table/AbstractTupleSelfTest.java
 
b/modules/table/src/test/java/org/apache/ignite/table/AbstractTupleSelfTest.java
new file mode 100644
index 0000000000..d1cc1fa53c
--- /dev/null
+++ 
b/modules/table/src/test/java/org/apache/ignite/table/AbstractTupleSelfTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.table;
+
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.Temporal;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.apache.ignite.internal.testframework.IgniteTestUtils;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tuple interface test.
+ */
+public abstract class AbstractTupleSelfTest {
+    private static final int NANOS_IN_SECOND = 9;
+    private static final int TIMESTAMP_PRECISION = 6;
+    private static final int TIME_PRECISION = 0;
+
+    private final Instant now;
+    private final BitSet bitSet;
+    private final byte[] bytes;
+    private final String string;
+    private final BigInteger bigInteger;
+    private final BigDecimal bigDecimal;
+
+    {
+        Random rnd = new Random();
+
+        now = Instant.now();
+        bitSet = randomBitSet(rnd, 12);
+        string = IgniteTestUtils.randomString(rnd, 14);
+        bytes = IgniteTestUtils.randomBytes(rnd, 13);
+        bigInteger = BigInteger.valueOf(rnd.nextLong());
+        bigDecimal = BigDecimal.valueOf(rnd.nextLong(), 5);
+    }
+
+    protected abstract Tuple createTuple();
+
+    /**
+     * Return {@code true} if tuple implementation is mutable, {@code false} 
otherwise.
+     * Note: when the method return {@code false}, then tests, which assumes 
relies on tuple mutability, will be skipped.
+     */
+    protected boolean isMutable() {
+        return true;
+    }
+
+    @Test
+    public void testValueReturnsValueByName() {
+        assertEquals(3L, (Long) getTuple().value("id"));
+        assertNull(getTuple().value("noValue"));
+
+        // Ensure unquoted name is case-insensitive
+        assertEquals("simple", getTuple().value("simplename"));
+        assertEquals("simple", getTuple().value("SimpleName"));
+        assertEquals("simple", getTuple().value("SIMPLENAME"));
+
+        assertEquals("simple", getTuple().value("\"SIMPLENAME\""));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("\"simplename\""));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("\"SimpleName\""));
+
+        // Ensure quoted name is case-sensitive
+        assertEquals("quoted", getTuple().value("\"QuotedName\""));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("\"Quotedname\""));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("\"QUOTEDNAME\""));
+
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("quotedname"));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("QuotedName"));
+        assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("QUOTEDNAME"));
+    }
+
+    @Test
+    public void testValueOrDefault() {
+        assertEquals(3L, getTuple().valueOrDefault("id", 1L));
+        assertNull(getTuple().valueOrDefault("noValue", "default"));
+
+        // Ensure unquoted name is case-insensitive
+        assertEquals("simple", getTuple().valueOrDefault("simplename", 
"default"));
+        assertEquals("simple", getTuple().valueOrDefault("SimpleName", 
"default"));
+        ;
+        assertEquals("simple", getTuple().valueOrDefault("SIMPLENAME", 
"default"));
+
+        assertEquals("simple", getTuple().valueOrDefault("\"SIMPLENAME\"", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("\"simplename\"", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("\"SimpleName\"", 
"default"));
+
+        // Ensure quoted name is case-sensitive
+        assertEquals("quoted", getTuple().valueOrDefault("\"QuotedName\"", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("\"Quotedname\"", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("\"QUOTEDNAME\"", 
"default"));
+
+        assertEquals("default", getTuple().valueOrDefault("quotedname", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("QuotedName", 
"default"));
+        assertEquals("default", getTuple().valueOrDefault("QUOTEDNAME", 
"default"));
+    }
+
+    @Test
+    public void testValueThrowsOnInvalidColumnName() {
+        var ex = assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("x"));
+        assertEquals("Column doesn't exist [name=x]", ex.getMessage());
+    }
+
+    @Test
+    public void testValueReturnsValueByIndex() {
+        assertEquals(3L, (Long) getTuple().value(0));
+        assertEquals("simple", getTuple().value(1));
+        assertEquals("quoted", getTuple().value(2));
+        assertNull(getTuple().value(3));
+    }
+
+    @Test
+    public void testValueThrowsOnInvalidIndex() {
+        var ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().value(-1));
+        assertEquals("Index -1 out of bounds for length 4", ex.getMessage());
+
+        ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().value(4));
+        assertEquals("Index 4 out of bounds for length 4", ex.getMessage());
+    }
+
+    @Test
+    public void testValueOrDefaultReturnsValueByName() {
+        assertEquals(3L, getTuple().valueOrDefault("id", -1L));
+        assertEquals("simple", getTuple().valueOrDefault("SimpleName", "y"));
+        assertNull(getTuple().valueOrDefault("noValue", "foo"));
+    }
+
+    @Test
+    public void testValueOrDefaultReturnsDefaultWhenColumnIsNotSet() {
+        assertEquals("foo", getTuple().valueOrDefault("x", "foo"));
+        assertNull(getTuple().valueOrDefault("x", null));
+    }
+
+    @Test
+    public void testValueReturnsOverwrittenValue() {
+        Assumptions.assumeTrue(isMutable(), "Immutable Tuple implementation.");
+
+        assertEquals("foo", getTuple().set("SimpleName", 
"foo").value("SimpleName"));
+        assertEquals("foo", getTuple().set("SimpleName", 
"foo").valueOrDefault("SimpleName", "bar"));
+    }
+
+    @Test
+    public void testValueOrDefaultReturnsOverwrittenValue() {
+        Assumptions.assumeTrue(isMutable(), "Immutable Tuple implementation.");
+
+        assertEquals("foo", getTuple().set("SimpleName", 
"foo").valueOrDefault("SimpleName", "bar"));
+        assertNull(getTuple().set("SimpleName", 
null).valueOrDefault("SimpleName", "foo"));
+    }
+
+    @Test
+    public void testColumnCount() {
+        Tuple tuple = getTuple();
+
+        assertEquals(4, tuple.columnCount());
+        assertEquals(4, tuple.set("id", -1).columnCount());
+
+        tuple.valueOrDefault("SimpleName", "foo");
+        assertEquals(4, tuple.columnCount());
+
+        tuple.valueOrDefault("foo", "bar");
+        assertEquals(4, tuple.columnCount());
+
+    }
+
+    @Test
+    public void testColumnCountReturnsActualSchemaSize() {
+        Assumptions.assumeTrue(isMutable(), "Immutable Tuple implementation.");
+
+        Tuple tuple = getTuple();
+
+        assertEquals(4, tuple.columnCount());
+
+        tuple.valueOrDefault("SimpleName", "foo");
+        assertEquals(4, tuple.columnCount());
+
+        tuple.valueOrDefault("foo", "bar");
+        assertEquals(4, tuple.columnCount());
+
+        tuple.set("foo", "bar");
+        assertEquals(5, tuple.columnCount());
+    }
+
+    @Test
+    public void testColumnNameReturnsNameByIndex() {
+        assertEquals("ID", getTuple().columnName(0));
+        assertEquals("SIMPLENAME", getTuple().columnName(1));
+        assertEquals("QuotedName", getTuple().columnName(2));
+        assertEquals("NOVALUE", getTuple().columnName(3));
+    }
+
+    @Test
+    public void testColumnNameThrowsOnInvalidIndex() {
+        var ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().columnName(-1));
+        assertEquals("Index -1 out of bounds for length 4", ex.getMessage());
+
+        ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().columnName(4));
+        assertEquals("Index 4 out of bounds for length 4", ex.getMessage());
+    }
+
+    @Test
+    public void testColumnIndexReturnsIndexByName() {
+        assertEquals(0, getTuple().columnIndex("id"));
+        assertEquals(1, getTuple().columnIndex("simplename"));
+        assertEquals(1, getTuple().columnIndex("SimpleName"));
+        assertEquals(1, getTuple().columnIndex("SIMPLENAME"));
+        assertEquals(1, getTuple().columnIndex("\"SIMPLENAME\""));
+        assertEquals(2, getTuple().columnIndex("\"QuotedName\""));
+    }
+
+    @Disabled
+    @Test
+    public void testColumnResolvableName() {
+        Tuple tuple = getTuple();
+
+        assertEquals(0, tuple.columnIndex(tuple.columnName(0)));
+        assertEquals(1, tuple.columnIndex(tuple.columnName(1)));
+        assertEquals(2, tuple.columnIndex(tuple.columnName(2)));
+        assertEquals(3, tuple.columnIndex(tuple.columnName(3)));
+    }
+
+    @Test
+    public void testColumnIndexForMissingColumns() {
+        assertEquals(-1, getTuple().columnIndex("foo"));
+
+        assertEquals(-1, getTuple().columnIndex("\"simplename\""));
+        assertEquals(-1, getTuple().columnIndex("\"SimpleName\""));
+
+        assertEquals(-1, getTuple().columnIndex("quotedname"));
+        assertEquals(-1, getTuple().columnIndex("QuotedName"));
+        assertEquals(-1, getTuple().columnIndex("QUOTEDNAME"));
+        assertEquals(-1, getTuple().columnIndex("\"quotedname\""));
+        assertEquals(-1, getTuple().columnIndex("\"QUTEDNAME\""));
+    }
+
+    @Test
+    public void testBasicTupleEquality() {
+        assertEquals(getTuple(), getTuple());
+        assertEquals(getTupleWithColumnOfAllTypes(), 
getTupleWithColumnOfAllTypes());
+    }
+
+    @Test
+    public void testMutableTupleEquality() {
+        Assumptions.assumeTrue(isMutable(), "Immutable Tuple implementation.");
+
+        assertEquals(createTuple(), createTuple());
+        assertEquals(createTuple().hashCode(), createTuple().hashCode());
+
+        assertEquals(createTuple().set("foo", null), createTuple().set("foo", 
null));
+        assertEquals(createTuple().set("foo", null).hashCode(), 
createTuple().set("foo", null).hashCode());
+
+        assertEquals(createTuple().set("foo", "bar"), createTuple().set("foo", 
"bar"));
+        assertEquals(createTuple().set("foo", "bar").hashCode(), 
createTuple().set("foo", "bar").hashCode());
+
+        assertNotEquals(createTuple().set("foo", null), 
createTuple().set("bar", null));
+        assertNotEquals(createTuple().set("foo", "foo"), 
createTuple().set("bar", "bar"));
+
+        assertEquals(createTuple().set("foo", "bar"), createTuple().set("FOO", 
"bar"));
+        assertEquals(createTuple().set("foo", "bar"), 
createTuple().set("\"FOO\"", "bar"));
+        assertEquals(createTuple().set("\"foo\"", "bar"), 
createTuple().set("\"foo\"", "bar"));
+
+        assertNotEquals(createTuple().set("foo", "foo"), 
createTuple().set("\"foo\"", "bar"));
+        assertNotEquals(createTuple().set("FOO", "foo"), 
createTuple().set("\"foo\"", "bar"));
+
+        Tuple tuple = createTuple();
+        Tuple tuple2 = createTuple();
+
+        assertEquals(tuple, tuple);
+
+        tuple.set("foo", "bar");
+
+        assertEquals(tuple, tuple);
+        assertNotEquals(tuple, tuple2);
+        assertNotEquals(tuple2, tuple);
+
+        tuple2.set("foo", "baz");
+
+        assertNotEquals(tuple, tuple2);
+        assertNotEquals(tuple2, tuple);
+
+        tuple2.set("foo", "bar");
+
+        assertEquals(tuple, tuple2);
+        assertEquals(tuple2, tuple);
+    }
+
+    @Test
+    public void testColumnNameCaseSensitivity() {
+        Tuple tuple = createTuple().set("foo", "bar").set("\"foo\"", 
"baz").set("\"Foo\"", null);
+
+        assertEquals(3, tuple.columnCount());
+        assertEquals("bar", tuple.value("foo"));
+        assertEquals("bar", tuple.value("Foo"));
+        assertEquals("bar", tuple.value("FOO"));
+        assertEquals("baz", tuple.value("\"foo\""));
+        assertNull(tuple.value("\"Foo\""));
+        assertNull(tuple.valueOrDefault("\"Foo\"", "baz"));
+    }
+
+    @Test
+    public void testVariousColumnTypes() {
+        Random rnd = new Random();
+
+        Tuple tuple = getTupleWithColumnOfAllTypes();
+
+        for (int i = 0; i < tuple.columnCount(); i++) {
+            String name = tuple.columnName(i);
+
+            if (tuple.value(i) instanceof byte[]) {
+                assertArrayEquals((byte[]) tuple.value(i), 
tuple.value(tuple.columnIndex(name)), "columnIdx=" + i);
+            } else {
+                assertEquals((Object) tuple.value(i), 
tuple.value(tuple.columnIndex(name)), "columnIdx=" + i);
+            }
+        }
+    }
+
+    @Test
+    public void testTupleEqualityDifferentColumnOrder() {
+        Assumptions.assumeTrue(isMutable(), "Immutable Tuple implementation.");
+
+        Random rnd = new Random();
+
+        Tuple tuple = getTupleWithColumnOfAllTypes();
+
+        List<Integer> randomIdx = IntStream.range(0, 
tuple.columnCount()).boxed().collect(Collectors.toList());
+
+        Collections.shuffle(randomIdx, rnd);
+
+        Tuple shuffledTuple = createTuple();
+
+        for (Integer i : randomIdx) {
+            shuffledTuple.set(tuple.columnName(i), tuple.value(i));
+        }
+
+        assertEquals(tuple, shuffledTuple);
+        assertEquals(tuple.hashCode(), shuffledTuple.hashCode());
+    }
+
+    @Test
+    public void testSerialization() throws Exception {
+        Tuple tup1 = getTupleWithColumnOfAllTypes();
+        Tuple tup2;
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        try (ObjectOutputStream os = new ObjectOutputStream(baos)) {
+            os.writeObject(tup1);
+        }
+
+        try (ObjectInputStream is = new ObjectInputStream(new 
ByteArrayInputStream(baos.toByteArray()))) {
+            tup2 = (Tuple) is.readObject();
+        }
+
+        assertEquals(tup1, tup2);
+    }
+
+    protected Tuple getTuple() {
+        return createTuple()
+                .set("id", 3L)
+                .set("SimpleName", "simple")
+                .set("\"QuotedName\"", "quoted")
+                .set("noValue", null);
+    }
+
+    protected Tuple getTupleWithColumnOfAllTypes() {
+        return createTuple().set("valByteCol", (byte) 1)
+                .set("valShortCol", (short) 2)
+                .set("valIntCol", 3)
+                .set("valLongCol", 4L)
+                .set("valFloatCol", 0.055f)
+                .set("valDoubleCol", 0.066d)
+                .set("valDateCol", LocalDate.ofInstant(now, 
ZoneId.systemDefault()))
+                .set("valDateTimeCol", 
truncateToDefaultPrecision(LocalDateTime.ofInstant(now, 
ZoneId.systemDefault())))
+                .set("valTimeCol", 
truncateToDefaultPrecision(LocalTime.ofInstant(now, ZoneId.systemDefault())))
+                .set("valTimeStampCol", truncateToDefaultPrecision(now))
+                .set("valBitmask1Col", bitSet)
+                .set("valBytesCol", bytes)
+                .set("valStringCol", string)
+                .set("valNumberCol", bigInteger)
+                .set("valDecimalCol", bigDecimal);
+    }
+
+    /**
+     * Returns random BitSet.
+     *
+     * @param rnd Random generator.
+     * @param bits Amount of bits in bitset.
+     */
+    private static BitSet randomBitSet(Random rnd, int bits) {
+        BitSet set = new BitSet();
+
+        for (int i = 0; i < bits; i++) {
+            if (rnd.nextBoolean()) {
+                set.set(i);
+            }
+        }
+
+        return set;
+    }
+
+    private <T extends Temporal> T truncateToDefaultPrecision(T temporal) {
+        int precision = temporal instanceof Instant ? TIMESTAMP_PRECISION
+                : TIME_PRECISION;
+
+        return (T) temporal.with(NANO_OF_SECOND,
+                truncatePrecision(temporal.get(NANO_OF_SECOND), 
tailFactor(precision)));
+    }
+
+    private int truncatePrecision(int nanos, int factor) {
+        return nanos / factor * factor;
+    }
+
+    private int tailFactor(int precision) {
+        if (precision >= NANOS_IN_SECOND) {
+            return 1;
+        }
+
+        return new BigInteger("10").pow(NANOS_IN_SECOND - 
precision).intValue();
+    }
+}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/table/TupleImplTest.java 
b/modules/table/src/test/java/org/apache/ignite/table/TupleImplTest.java
index 910fa27c45..0a5d8a89ff 100644
--- a/modules/table/src/test/java/org/apache/ignite/table/TupleImplTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/table/TupleImplTest.java
@@ -17,32 +17,9 @@
 
 package org.apache.ignite.table;
 
-import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.randomBitSet;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import org.apache.ignite.internal.testframework.IgniteTestUtils;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -50,244 +27,10 @@ import org.junit.jupiter.api.Test;
  *
  * <p>Should be in sync with org.apache.ignite.client.ClientTupleBuilderTest.
  */
-public class TupleImplTest {
-    @Test
-    public void testValueReturnsValueByName() {
-        assertEquals(3L, (Long) getTuple().value("id"));
-        assertEquals("Shirt", getTuple().value("name"));
-    }
-
-    @Test
-    public void testValueThrowsOnInvalidColumnName() {
-        var ex = assertThrows(IllegalArgumentException.class, () -> 
getTuple().value("x"));
-        assertEquals("Column doesn't exist [name=x]", ex.getMessage());
-    }
-
-    @Test
-    public void testValueReturnsValueByIndex() {
-        assertEquals(3L, (Long) getTuple().value(0));
-        assertEquals("Shirt", getTuple().value(1));
-    }
-
-    @Test
-    public void testValueThrowsOnInvalidIndex() {
-        var ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().value(-1));
-        assertEquals("Index -1 out of bounds for length 2", ex.getMessage());
-
-        ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().value(3));
-        assertEquals("Index 3 out of bounds for length 2", ex.getMessage());
-    }
-
-    @Test
-    public void testValueOrDefaultReturnsValueByName() {
-        assertEquals(3L, getTuple().valueOrDefault("id", -1L));
-        assertEquals("Shirt", getTuple().valueOrDefault("name", "y"));
-    }
-
-    @Test
-    public void testValueOrDefaultReturnsDefaultWhenColumnIsNotSet() {
-        assertEquals("foo", createTuple().valueOrDefault("x", "foo"));
-    }
-
-    @Test
-    public void testValueReturnsOverwrittenValue() {
-        assertEquals("foo", createTuple().set("name", "foo").value("name"));
-        assertEquals("foo", createTuple().set("name", 
"foo").valueOrDefault("name", "bar"));
-    }
-
-    @Test
-    public void testValueOrDefaultReturnsNullWhenColumnIsSetToNull() {
-        assertNull(createTuple().set("name", null).valueOrDefault("name", 
"foo"));
-
-        // Overwritten column.
-        assertNull(getTuple().set("name", null).valueOrDefault("name", "foo"));
-    }
-
-    @Test
-    public void testColumnCountReturnsSchemaSize() {
-        assertEquals(0, createTuple().columnCount());
-
-        Tuple tuple = getTuple();
-
-        assertEquals(2, tuple.columnCount());
-        assertEquals(2, tuple.set("id", -1).columnCount());
-
-        tuple.valueOrDefault("name", "foo");
-        assertEquals(2, tuple.columnCount());
-
-        tuple.valueOrDefault("foo", "bar");
-        assertEquals(2, tuple.columnCount());
-
-        tuple.set("foo", "bar");
-        assertEquals(3, tuple.columnCount());
-    }
-
-    @Test
-    public void testColumnNameReturnsNameByIndex() {
-        assertEquals("ID", getTuple().columnName(0));
-        assertEquals("NAME", getTuple().columnName(1));
-    }
-
-    @Test
-    public void testColumnNameThrowsOnInvalidIndex() {
-        var ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().columnName(-1));
-        assertEquals("Index -1 out of bounds for length 2", ex.getMessage());
-
-        ex = assertThrows(IndexOutOfBoundsException.class, () -> 
getTuple().columnName(3));
-        assertEquals("Index 3 out of bounds for length 2", ex.getMessage());
-    }
-
-    @Test
-    public void testColumnIndexReturnsIndexByName() {
-        assertEquals(0, getTuple().columnIndex("id"));
-        assertEquals(1, getTuple().columnIndex("name"));
-    }
-
-    @Test
-    public void testColumnIndexForMissingColumns() {
-        assertEquals(-1, getTuple().columnIndex("foo"));
-    }
-
-    @Test
-    public void testVariousColumnTypes() {
-        Random rnd = new Random();
-
-        Tuple tuple = new TupleImpl()
-                .set("valByteCol", (byte) 1)
-                .set("valShortCol", (short) 2)
-                .set("valIntCol", 3)
-                .set("valLongCol", 4L)
-                .set("valFloatCol", 0.055f)
-                .set("valDoubleCol", 0.066d)
-                .set("keyUuidCol", UUID.randomUUID())
-                .set("valDateCol", LocalDate.now())
-                .set("valDateTimeCol", LocalDateTime.now())
-                .set("valTimeCol", LocalTime.now())
-                .set("valTimeStampCol", Instant.now())
-                .set("valBitmask1Col", randomBitSet(rnd, 12))
-                .set("valBytesCol", IgniteTestUtils.randomBytes(rnd, 13))
-                .set("valStringCol", IgniteTestUtils.randomString(rnd, 14))
-                .set("valNumberCol", BigInteger.valueOf(rnd.nextLong()))
-                .set("valDecimalCol", BigDecimal.valueOf(rnd.nextLong(), 5));
-
-        for (int i = 0; i < tuple.columnCount(); i++) {
-            String name = tuple.columnName(i);
-
-            if (tuple.value(i) instanceof byte[]) {
-                assertArrayEquals((byte[]) tuple.value(i), 
tuple.value(tuple.columnIndex(name)), "columnIdx=" + i);
-            } else {
-                assertEquals((Object) tuple.value(i), 
tuple.value(tuple.columnIndex(name)), "columnIdx=" + i);
-            }
-        }
-    }
-
-    @Test
-    public void testBasicTupleEquality() {
-        assertEquals(new TupleImpl(), new TupleImpl());
-        assertEquals(new TupleImpl().hashCode(), new TupleImpl().hashCode());
-
-        assertEquals(new TupleImpl().set("foo", null), new 
TupleImpl().set("foo", null));
-        assertEquals(new TupleImpl().set("foo", null).hashCode(), new 
TupleImpl().set("foo", null).hashCode());
-
-        assertEquals(new TupleImpl().set("foo", "bar"), new 
TupleImpl().set("foo", "bar"));
-        assertEquals(new TupleImpl().set("foo", "bar").hashCode(), new 
TupleImpl().set("foo", "bar").hashCode());
-
-        assertNotEquals(new TupleImpl().set("foo", null), new 
TupleImpl().set("bar", null));
-        assertNotEquals(new TupleImpl().set("foo", "foo"), new 
TupleImpl().set("bar", "bar"));
-
-        TupleImpl tuple = new TupleImpl();
-        final TupleImpl tuple2 = new TupleImpl();
-
-        assertEquals(tuple, tuple);
-
-        tuple.set("foo", "bar");
-
-        assertEquals(tuple, tuple);
-        assertNotEquals(tuple, tuple2);
-        assertNotEquals(tuple2, tuple);
-
-        tuple2.set("foo", "baz");
-
-        assertNotEquals(tuple, tuple2);
-        assertNotEquals(tuple2, tuple);
-
-        tuple2.set("foo", "bar");
-
-        assertEquals(tuple, tuple2);
-        assertEquals(tuple2, tuple);
-    }
-
-    @Test
-    public void testTupleEquality() {
-        Random rnd = new Random();
-
-        Tuple tuple = new TupleImpl()
-                .set("valByteCol", (byte) 1)
-                .set("valShortCol", (short) 2)
-                .set("valIntCol", 3)
-                .set("valLongCol", 4L)
-                .set("valFloatCol", 0.055f)
-                .set("valDoubleCol", 0.066d)
-                .set("keyUuidCol", UUID.randomUUID())
-                .set("valDateCol", LocalDate.now())
-                .set("valDateTimeCol", LocalDateTime.now())
-                .set("valTimeCol", LocalTime.now())
-                .set("valTimeStampCol", Instant.now())
-                .set("valBitmask1Col", randomBitSet(rnd, 12))
-                .set("valBytesCol", IgniteTestUtils.randomBytes(rnd, 13))
-                .set("valStringCol", IgniteTestUtils.randomString(rnd, 14))
-                .set("valNumberCol", BigInteger.valueOf(rnd.nextLong()))
-                .set("valDecimalCol", BigDecimal.valueOf(rnd.nextLong(), 5));
-
-        List<Integer> randomIdx = IntStream.range(0, 
tuple.columnCount()).boxed().collect(Collectors.toList());
-
-        Collections.shuffle(randomIdx, rnd);
-
-        Tuple shuffledTuple = new TupleImpl();
-
-        for (Integer i : randomIdx) {
-            shuffledTuple.set(tuple.columnName(i), tuple.value(i));
-        }
-
-        assertEquals(tuple, shuffledTuple);
-        assertEquals(tuple.hashCode(), shuffledTuple.hashCode());
-    }
-
-    @Test
-    public void testSerialization() throws IOException, ClassNotFoundException 
{
-        Random rnd = new Random();
-
-        Tuple tup1 = new TupleImpl()
-                .set("valByteCol", (byte) 1)
-                .set("valShortCol", (short) 2)
-                .set("valIntCol", 3)
-                .set("valLongCol", 4L)
-                .set("valFloatCol", 0.055f)
-                .set("valDoubleCol", 0.066d)
-                .set("keyUuidCol", UUID.randomUUID())
-                .set("valDateCol", LocalDate.now())
-                .set("valDateTimeCol", LocalDateTime.now())
-                .set("valTimeCol", LocalTime.now())
-                .set("valTimeStampCol", Instant.now())
-                .set("valBitmask1Col", randomBitSet(rnd, 12))
-                .set("valBytesCol", IgniteTestUtils.randomBytes(rnd, 13))
-                .set("valStringCol", IgniteTestUtils.randomString(rnd, 14))
-                .set("valNumberCol", BigInteger.valueOf(rnd.nextLong()))
-                .set("valDecimalCol", BigDecimal.valueOf(rnd.nextLong(), 5));
-
-        Tuple tup2;
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-        try (ObjectOutputStream os = new ObjectOutputStream(baos)) {
-            os.writeObject(tup1);
-        }
-
-        try (ObjectInputStream is = new ObjectInputStream(new 
ByteArrayInputStream(baos.toByteArray()))) {
-            tup2 = (Tuple) is.readObject();
-        }
-
-        assertEquals(tup1, tup2);
+public class TupleImplTest extends AbstractTupleSelfTest {
+    @Override
+    protected Tuple createTuple() {
+        return new TupleImpl();
     }
 
     @Test
@@ -300,15 +43,7 @@ public class TupleImplTest {
 
         assertEquals(Tuple.create().set("id", 42L).set("name", "universe"),
                 Tuple.create(Tuple.create().set("id", 42L).set("name", 
"universe")));
-    }
-
-    private static TupleImpl createTuple() {
-        return new TupleImpl();
-    }
 
-    private static Tuple getTuple() {
-        return new TupleImpl()
-                .set("id", 3L)
-                .set("name", "Shirt");
+        assertEquals(getTuple(), Tuple.create(getTuple()));
     }
 }


Reply via email to