content: /*
   * 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.arrow.vector.table;
  
  import static org.apache.arrow.vector.table.TestUtils.INT_VECTOR_NAME_1;
  import static org.apache.arrow.vector.table.TestUtils.twoIntColumns;
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertNotNull;
  import static org.junit.jupiter.api.Assertions.assertTrue;
  
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import org.apache.arrow.memory.BufferAllocator;
  import org.apache.arrow.memory.RootAllocator;
  import org.apache.arrow.vector.FieldVector;
  import org.apache.arrow.vector.IntVector;
  import org.apache.arrow.vector.VectorSchemaRoot;
  import org.apache.arrow.vector.types.pojo.ArrowType;
  import org.apache.arrow.vector.types.pojo.Field;
  import org.apache.arrow.vector.types.pojo.FieldType;
  import org.apache.arrow.vector.types.pojo.Schema;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  
  class TableTest {
  
    private final ArrowType intArrowType = new ArrowType.Int(32, true);
    private final FieldType intFieldType = new FieldType(true, intArrowType, null);
  
    private BufferAllocator allocator;
  
    @BeforeEach
    public void init() {
      allocator = new RootAllocator(Long.MAX_VALUE);
    }
  
    @Test
    void of() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = Table.of(vectorList.toArray(new FieldVector[2]))) {
        Row c = t.immutableRow();
        assertEquals(2, t.getRowCount());
        assertEquals(2, t.getVectorCount());
        IntVector intVector1 = (IntVector) vectorList.get(0);
        assertEquals(INT_VECTOR_NAME_1, intVector1.getName());
        c.setPosition(0);
  
        // Now test changes to the first vector
        // first Table value is 1
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
  
        // original vector is updated to set first value to 44
        intVector1.setSafe(0, 44);
        assertEquals(44, intVector1.get(0));
  
        // first Table value is still 1 for the zeroth vector
        assertEquals(1, c.getInt(0));
      }
    }
  
    @Test
    void constructor() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList, 2)) {
        assertEquals(2, t.getRowCount());
        assertEquals(2, t.getVectorCount());
        Row c = t.immutableRow();
        IntVector intVector1 = (IntVector) vectorList.get(0);
        c.setPosition(0);
  
        // Now test changes to the first vector
        // first Table value is 1
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
  
        // original vector is updated to set first value to 44
        intVector1.setSafe(0, 44);
        assertEquals(44, intVector1.get(0));
        assertEquals(44, ((IntVector) vectorList.get(0)).get(0));
  
        // first Table value is still 1 for the zeroth vector
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
      }
    }
  
    /**
     * Tests construction with an iterable that's not a list (there is a specialty constructor for
     * Lists).
     */
    @Test
    void constructor2() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      Iterable<FieldVector> iterable = new HashSet<>(vectorList);
      try (Table t = new Table(iterable)) {
        assertEquals(2, t.getRowCount());
        assertEquals(2, t.getVectorCount());
        Row c = t.immutableRow();
        IntVector intVector1 = (IntVector) vectorList.get(0);
        c.setPosition(0);
  
        // Now test changes to the first vector
        // first Table value is 1
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
  
        // original vector is updated to set first value to 44
        intVector1.setSafe(0, 44);
        assertEquals(44, intVector1.get(0));
        assertEquals(44, ((IntVector) vectorList.get(0)).get(0));
  
        // first Table value is still 1 for the zeroth vector
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
      }
    }
  
    @Test
    void copy() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        assertEquals(2, t.getVectorCount());
        try (Table copy = t.copy()) {
          for (FieldVector v : t.fieldVectors) {
            FieldVector vCopy = copy.getVector(v.getName());
            assertNotNull(vCopy);
            assertEquals(v.getValueCount(), vCopy.getValueCount());
            for (int i = 0; i < v.getValueCount(); i++) {
              Integer vValue = ((IntVector) v).getObject(i);
              Integer vCopyValue = ((IntVector) vCopy).getObject(i);
              assertEquals(vValue, vCopyValue);
            }
          }
        }
      }
    }
  
    @Test
    void addVector() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        IntVector v3 = new IntVector("3", intFieldType, allocator);
        Table t2 = t.addVector(2, v3);
        assertEquals(3, t2.fieldVectors.size());
        assertTrue(t2.getVector("3").isNull(0));
        assertTrue(t2.getVector("3").isNull(1));
        t2.close();
      }
    }
  
    @Test
    void removeVector() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      IntVector v2 = (IntVector) vectorList.get(1);
      int val1 = v2.get(0);
      int val2 = v2.get(1);
      try (Table t = new Table(vectorList)) {
  
        Table t2 = t.removeVector(0);
        assertEquals(1, t2.fieldVectors.size());
        assertEquals(val1, ((IntVector) t2.getVector(0)).get(0));
        assertEquals(val2, ((IntVector) t2.getVector(0)).get(1));
      }
    }
  
    /** Tests table iterator in enhanced for loop. */
    @Test
    void iterator1() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        Iterator<Row> iterator = t.iterator();
        assertNotNull(iterator);
        assertTrue(iterator.hasNext());
        int sum = 0;
        for (Row row : t) {
          sum += row.getInt(0);
        }
        assertEquals(3, sum);
      }
    }
  
    /** Tests explicit iterator. */
    @SuppressWarnings("WhileLoopReplaceableByForEach")
    @Test
    void iterator2() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        Iterator<Row> iterator = t.iterator();
        assertNotNull(iterator);
        assertTrue(iterator.hasNext());
        int sum = 0;
        Iterator<Row> it = t.iterator();
        while (it.hasNext()) {
          Row row = it.next();
          sum += row.getInt(0);
        }
        assertEquals(3, sum);
      }
    }
  
    /**
     * Tests a slice operation where no length is provided, so the range extends to the end of the
     * table.
     */
    @Test
    void sliceToEnd() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        Table slice = t.slice(1);
        assertEquals(1, slice.rowCount);
        assertEquals(2, t.rowCount); // memory is copied for slice, not transferred
        slice.close();
      }
    }
  
    /** Tests a slice operation with a given length parameter. */
    @Test
    void sliceRange() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (Table t = new Table(vectorList)) {
        Table slice = t.slice(1, 1);
        assertEquals(1, slice.rowCount);
        assertEquals(2, t.rowCount); // memory is copied for slice, not transferred
        slice.close();
      }
    }
  
    /**
     * Tests creation of a table from a VectorSchemaRoot.
     *
     * <p>Also tests that updates to the source Vectors do not impact the values in the Table
     */
    @Test
    void constructFromVsr() {
      List<FieldVector> vectorList = twoIntColumns(allocator);
      try (VectorSchemaRoot vsr = new VectorSchemaRoot(vectorList)) {
        Table t = new Table(vsr);
        Row c = t.immutableRow();
        assertEquals(2, t.rowCount);
        assertEquals(0, vsr.getRowCount()); // memory is copied for slice, not transferred
        IntVector intVector1 = (IntVector) vectorList.get(0);
        c.setPosition(0);
  
        // Now test changes to the first vector
        // first Table value is 1
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
  
        // original vector is updated to set first value to 44
        intVector1.setSafe(0, 44);
        assertEquals(44, intVector1.get(0));
        assertEquals(44, ((IntVector) vsr.getVector(0)).get(0));
  
        // first Table value is still 1 for the zeroth vector
        assertEquals(1, c.getInt(INT_VECTOR_NAME_1));
  
        // TEST FIELDS //
        Schema schema = t.schema;
        Field f1 = t.getField(INT_VECTOR_NAME_1);
        FieldVector fv1 = vectorList.get(0);
        assertEquals(f1, fv1.getField());
        assertEquals(f1, schema.findField(INT_VECTOR_NAME_1));
        t.close();
      }
    }
  }
  