public TableMetadata updateSchema(Schema newSchema, int newLastColumnId) {
    return new Builder(this).setCurrentSchema(newSchema, newLastColumnId).build();
  }
@Test
  public void testUpdateSchema() {
    Schema schema =
        new Schema(0, Types.NestedField.required(1, "y", Types.LongType.get(), "comment"));
    TableMetadata freshTable =
        TableMetadata.newTableMetadata(
            schema, PartitionSpec.unpartitioned(), null, ImmutableMap.of());
    assertThat(freshTable.currentSchemaId()).isEqualTo(TableMetadata.INITIAL_SCHEMA_ID);
    assertSameSchemaList(ImmutableList.of(schema), freshTable.schemas());
    assertThat(freshTable.schema().asStruct()).isEqualTo(schema.asStruct());
    assertThat(freshTable.lastColumnId()).isEqualTo(1);

    // update schema
    Schema schema2 =
        new Schema(
            Types.NestedField.required(1, "y", Types.LongType.get(), "comment"),
            Types.NestedField.required(2, "x", Types.StringType.get()));
    TableMetadata twoSchemasTable = freshTable.updateSchema(schema2, 2);
    assertThat(twoSchemasTable.currentSchemaId()).isEqualTo(1);
    assertSameSchemaList(
        ImmutableList.of(schema, new Schema(1, schema2.columns())), twoSchemasTable.schemas());
    assertThat(twoSchemasTable.schema().asStruct()).isEqualTo(schema2.asStruct());
    assertThat(twoSchemasTable.lastColumnId()).isEqualTo(2);

    // update schema with the same schema and last column ID as current shouldn't cause change
    Schema sameSchema2 =
        new Schema(
            Types.NestedField.required(1, "y", Types.LongType.get(), "comment"),
            Types.NestedField.required(2, "x", Types.StringType.get()));
    TableMetadata sameSchemaTable = twoSchemasTable.updateSchema(sameSchema2, 2);
    assertThat(sameSchemaTable).isSameAs(twoSchemasTable);

    // update schema with the same schema and different last column ID as current should create
    // a new table
    TableMetadata differentColumnIdTable = sameSchemaTable.updateSchema(sameSchema2, 3);
    assertThat(differentColumnIdTable.currentSchemaId()).isEqualTo(1);
    assertSameSchemaList(
        ImmutableList.of(schema, new Schema(1, schema2.columns())),
        differentColumnIdTable.schemas());
    assertThat(differentColumnIdTable.schema().asStruct()).isEqualTo(schema2.asStruct());
    assertThat(differentColumnIdTable.lastColumnId()).isEqualTo(3);

    // update schema with old schema does not change schemas
    TableMetadata revertSchemaTable = differentColumnIdTable.updateSchema(schema, 3);
    assertThat(revertSchemaTable.currentSchemaId()).isEqualTo(0);
    assertSameSchemaList(
        ImmutableList.of(schema, new Schema(1, schema2.columns())), revertSchemaTable.schemas());
    assertThat(revertSchemaTable.schema().asStruct()).isEqualTo(schema.asStruct());
    assertThat(revertSchemaTable.lastColumnId()).isEqualTo(3);

    // create new schema will use the largest schema id + 1
    Schema schema3 =
        new Schema(
            Types.NestedField.required(2, "y", Types.LongType.get(), "comment"),
            Types.NestedField.required(4, "x", Types.StringType.get()),
            Types.NestedField.required(6, "z", Types.IntegerType.get()));
    TableMetadata threeSchemaTable = revertSchemaTable.updateSchema(schema3, 6);
    assertThat(threeSchemaTable.currentSchemaId()).isEqualTo(2);
    assertSameSchemaList(
        ImmutableList.of(
            schema, new Schema(1, schema2.columns()), new Schema(2, schema3.columns())),
        threeSchemaTable.schemas());
    assertThat(threeSchemaTable.schema().asStruct()).isEqualTo(schema3.asStruct());
    assertThat(threeSchemaTable.lastColumnId()).isEqualTo(6);
  }