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

liuxun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 171f7fb486 [#6799] feat(clients/cli): Suport `TableFormat`, 
`PlainFormat` for `Tag` (#6847)
171f7fb486 is described below

commit 171f7fb486578716d814b5520e4518ecc4e11dca
Author: Eric Chang <[email protected]>
AuthorDate: Mon May 12 18:34:01 2025 +0800

    [#6799] feat(clients/cli): Suport `TableFormat`, `PlainFormat` for `Tag` 
(#6847)
    
    ### What changes were proposed in this pull request?
    
    This PR introduce table format and plain format to display the results
    in `gcli.sh`.
    
    ### Why are the changes needed?
    
    Support different formats of results.
    
    Fix: #6799
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes, it introduce plain format and table format to display results of
    commands.
    
    ### How was this patch tested?
    
    Tested manually and by `TestTableFormat` and `TestPlainFormat`.
    
    This are steps to reproduce test result:
    
    ```
    # build distribution
    ./gradlew clean compileDistribution -x test
    cd distribution/package/bin
    
    # start gravitino server
    ./gravitino.sh start
    
    # create metalake
    ./gcli.sh metalake create --metalake my_metalake --comment "This is my 
metalake"
    
    my_metalake created
    
    # create tags
    ./gcli.sh tag create --metalake my_metalake --tag tagA tagB
    
    # set properties
    ./gcli.sh tag set --metalake my_metalake --tag tagA --property key1 --value 
value1
    tagA property set.
    
    ./gcli.sh tag set --metalake my_metalake --tag tagB --property key2 --value 
value2
    tagB property set.
    
    # list properties with plain format
    ./gcli.sh  tag properties --metalake my_metalake --tag tagA
    key,value
    key1,value1
    
    # list properties with table format
    ./gcli.sh tag properties --metalake my_metalake --tag tagA --output table
    +------+--------+
    | Key  | Value  |
    +------+--------+
    | key1 | value1 |
    +------+--------+
    
    # list tags with plain format
    ./gcli.sh tag list --metalake my_metalake
    name
    tagA
    tagB
    
    # list tags with table format
    ./gcli.sh tag list --metalake my_metalake --output table
    
    +------+
    | Name |
    +------+
    | tagA |
    | tagB |
    +------+
    
    # list properties with plain format
    ./gcli.sh tag properties --metalake my_metalake --tag tagA
    key,value
    key1,value1
    test,value
    
    # list properties with table format
    ./gcli.sh tag properties --metalake my_metalake --tag tagA --output table
    
    +------+--------+
    | Key  | Value  |
    +------+--------+
    | key1 | value1 |
    | test | value  |
    +------+--------+
    
    
    # add comment to tag
    ./gcli.sh tag update --metalake my_metalake --tag tagA --comment "new 
comment"
    tagA comment changed.
    
    # show details in plain format
    ./gcli.sh tag details --metalake my_metalake --tag tagA
    name,comment
    tagA,new comment
    
    # show details in table format
    ./gcli.sh tag details --metalake my_metalake --tag tagA --output table
    +------+-------------+
    | Name |   Comment   |
    +------+-------------+
    | tagA | new comment |
    +------+-------------+
    
    ```
---
 .../apache/gravitino/cli/commands/ListAllTags.java |   7 +-
 .../gravitino/cli/commands/ListProperties.java     |   8 +-
 .../gravitino/cli/commands/ListTagProperties.java  |   8 +-
 .../apache/gravitino/cli/commands/TagDetails.java  |   2 +-
 .../org/apache/gravitino/cli/outputs/LineUtil.java |  12 +++
 .../apache/gravitino/cli/outputs/PlainFormat.java  |  83 +++++++++++++++-
 .../apache/gravitino/cli/outputs/TableFormat.java  |  95 +++++++++++++++++-
 .../gravitino/cli/output/TestPlainFormat.java      |  60 ++++++++++++
 .../gravitino/cli/output/TestTableFormat.java      | 107 +++++++++++++++++++++
 9 files changed, 367 insertions(+), 15 deletions(-)

diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListAllTags.java 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListAllTags.java
index 63657bb0fd..a5fcd2a402 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListAllTags.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListAllTags.java
@@ -23,6 +23,7 @@ import org.apache.gravitino.cli.CommandContext;
 import org.apache.gravitino.cli.ErrorMessages;
 import org.apache.gravitino.client.GravitinoClient;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.tag.Tag;
 
 /* Lists all tags in a metalake. */
 public class ListAllTags extends Command {
@@ -43,10 +44,10 @@ public class ListAllTags extends Command {
   /** Lists all tags in a metalake. */
   @Override
   public void handle() {
-    String[] tags = new String[0];
+    Tag[] tags = new Tag[] {};
     try {
       GravitinoClient client = buildClient(metalake);
-      tags = client.listTags();
+      tags = client.listTagsInfo();
     } catch (NoSuchMetalakeException err) {
       exitWithError(ErrorMessages.UNKNOWN_METALAKE);
     } catch (Exception exp) {
@@ -56,7 +57,7 @@ public class ListAllTags extends Command {
     if (tags.length == 0) {
       printInformation("No tags exist.");
     } else {
-      printResults(String.join(",", tags));
+      printResults(tags);
     }
   }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListProperties.java
 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListProperties.java
index 5ad7e53256..5625621e33 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListProperties.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListProperties.java
@@ -45,12 +45,6 @@ public class ListProperties extends Command {
    * @param properties The name, value pairs of properties.
    */
   public void printProperties(Map<String, String> properties) {
-    StringBuilder all = new StringBuilder();
-
-    for (Map.Entry<String, String> property : properties.entrySet()) {
-      all.append(property.getKey() + "," + property.getValue() + 
System.lineSeparator());
-    }
-
-    System.out.print(all);
+    printResults(properties);
   }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTagProperties.java
 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTagProperties.java
index 13ace743f7..6e2b5f73ed 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTagProperties.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTagProperties.java
@@ -19,6 +19,7 @@
 
 package org.apache.gravitino.cli.commands;
 
+import java.util.Collections;
 import java.util.Map;
 import org.apache.gravitino.cli.CommandContext;
 import org.apache.gravitino.cli.ErrorMessages;
@@ -61,7 +62,10 @@ public class ListTagProperties extends ListProperties {
       exitWithError(exp.getMessage());
     }
 
-    Map<String, String> properties = gTag.properties();
-    printProperties(properties);
+    if (gTag != null) {
+      Map<String, String> props =
+          gTag.properties() != null ? gTag.properties() : 
Collections.emptyMap();
+      printProperties(props);
+    }
   }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagDetails.java 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagDetails.java
index 75b127cf55..e3d1073143 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagDetails.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagDetails.java
@@ -61,7 +61,7 @@ public class TagDetails extends Command {
     }
 
     if (result != null) {
-      printResults(result.name() + "," + result.comment());
+      printResults(result);
     }
   }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/LineUtil.java 
b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/LineUtil.java
index 356a588953..95052f18d2 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/LineUtil.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/LineUtil.java
@@ -26,6 +26,7 @@ import org.apache.gravitino.rel.expressions.Expression;
 import org.apache.gravitino.rel.expressions.FunctionExpression;
 import org.apache.gravitino.rel.expressions.literals.Literal;
 import org.apache.gravitino.rel.types.Type;
+import org.apache.gravitino.tag.Tag;
 
 public class LineUtil {
   // This expression is primarily used to match characters that have a display 
width of
@@ -34,6 +35,7 @@ public class LineUtil {
       Pattern.compile(
           
"[\u1100-\u115F\u2E80-\uA4CF\uAC00-\uD7A3\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE6F\uFF00-\uFF60\uFFE0-\uFFE6]");
   public static final String EMPTY_DEFAULT_VALUE = "";
+  public static final String NULL_DEFAULT_VALUE = "N/A";
   public static final String EMPTY_STRING_TYPE_DEFAULT_VALUE = "''";
 
   /**
@@ -191,4 +193,14 @@ public class LineUtil {
   public static String getComment(org.apache.gravitino.rel.Column column) {
     return column.comment() == null ? "N/A" : column.comment();
   }
+
+  /**
+   * Get the comment of a tag. If the tag does not have a comment, return 
"N/A".
+   *
+   * @param tag the tag to get.
+   * @return the comment of the tag.
+   */
+  static String getComment(Tag tag) {
+    return tag.comment() == null ? "N/A" : tag.comment();
+  }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java 
b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java
index 649c676e0b..6418021c29 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.cli.outputs;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 import org.apache.gravitino.Audit;
 import org.apache.gravitino.Catalog;
@@ -31,6 +32,7 @@ import org.apache.gravitino.cli.CommandContext;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.rel.Column;
 import org.apache.gravitino.rel.Table;
+import org.apache.gravitino.tag.Tag;
 
 /** Plain format to print a pretty string to standard out. */
 public abstract class PlainFormat<T> extends BaseOutputFormat<T> {
@@ -76,8 +78,15 @@ public abstract class PlainFormat<T> extends 
BaseOutputFormat<T> {
       new AuditPlainFormat(context).output((Audit) entity);
     } else if (entity instanceof Column[]) {
       new ColumnListPlainFormat(context).output((Column[]) entity);
+    } else if (entity instanceof Tag) {
+      new TagDetailsPlainFormat(context).output((Tag) entity);
+    } else if (entity instanceof Tag[]) {
+      new TagListPlainFormat(context).output((Tag[]) entity);
+    } else if (entity instanceof Map) {
+      new PropertiesListPlainFormat(context).output((Map<?, ?>) entity);
     } else {
-      throw new IllegalArgumentException("Unsupported object type");
+      throw new IllegalArgumentException(
+          "Unsupported object type: " + (entity == null ? "null" : 
entity.getClass().getName()));
     }
   }
 
@@ -404,4 +413,76 @@ public abstract class PlainFormat<T> extends 
BaseOutputFormat<T> {
       return 
COMMA_JOINER.join(Arrays.stream(groups).map(Group::name).collect(Collectors.toList()));
     }
   }
+
+  /**
+   * Formats detail information of {@link org.apache.gravitino.tag.Tag}. 
Output format: name,
+   * comment
+   */
+  static final class TagDetailsPlainFormat extends PlainFormat<Tag> {
+
+    /**
+     * Creates a new {@link TagDetailsPlainFormat}.
+     *
+     * @param context The command context.
+     */
+    public TagDetailsPlainFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Tag tag) {
+      String comment = tag.comment() == null ? "N/A" : tag.comment();
+      return COMMA_JOINER.join(tag.name(), comment);
+    }
+  }
+
+  /** Formats array of {@link org.apache.gravitino.tag.Tag} information. 
Output format: name */
+  static final class TagListPlainFormat extends PlainFormat<Tag[]> {
+
+    /**
+     * Creates a new {@link TagListPlainFormat}.
+     *
+     * @param context The command context.
+     */
+    public TagListPlainFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Tag[] tags) {
+      List<String> tagNames = 
Arrays.stream(tags).map(Tag::name).collect(Collectors.toList());
+      return NEWLINE_JOINER.join(tagNames);
+    }
+  }
+
+  /**
+   * Formats information about properties of {@link 
org.apache.gravitino.tag.Tag}. Output format:
+   * key, value
+   */
+  static final class PropertiesListPlainFormat extends PlainFormat<Map<?, ?>> {
+
+    /**
+     * Creates a new {@link PropertiesListPlainFormat}.
+     *
+     * @param context The command context.
+     */
+    public PropertiesListPlainFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Map<?, ?> properties) {
+      StringBuilder data = new StringBuilder();
+      properties.forEach(
+          (key, value) -> {
+            data.append(COMMA_JOINER.join(key.toString(), value.toString()));
+            data.append(System.lineSeparator());
+          });
+
+      return data.toString();
+    }
+  }
 }
diff --git 
a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java 
b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java
index c4e556abd3..a34602f11b 100644
--- 
a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java
+++ 
b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/TableFormat.java
@@ -44,6 +44,7 @@ import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import org.apache.gravitino.Audit;
 import org.apache.gravitino.Catalog;
@@ -55,6 +56,7 @@ import org.apache.gravitino.cli.CommandContext;
 import org.apache.gravitino.cli.commands.Command;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.rel.Table;
+import org.apache.gravitino.tag.Tag;
 
 /**
  * Abstract base class for formatting entity information into ASCII-art 
tables. Provides
@@ -106,8 +108,15 @@ public abstract class TableFormat<T> extends 
BaseOutputFormat<T> {
       new AuditTableFormat(context).output((Audit) entity);
     } else if (entity instanceof org.apache.gravitino.rel.Column[]) {
       new 
ColumnListTableFormat(context).output((org.apache.gravitino.rel.Column[]) 
entity);
+    } else if (entity instanceof Tag) {
+      new TagDetailsTableFormat(context).output((Tag) entity);
+    } else if (entity instanceof Tag[]) {
+      new TagListTableFormat(context).output((Tag[]) entity);
+    } else if (entity instanceof Map) {
+      new PropertiesListTableFormat(context).output((Map<?, ?>) entity);
     } else {
-      throw new IllegalArgumentException("Unsupported object type");
+      throw new IllegalArgumentException(
+          "Unsupported object type: " + (entity == null ? "null" : 
entity.getClass().getName()));
     }
   }
 
@@ -902,4 +911,88 @@ public abstract class TableFormat<T> extends 
BaseOutputFormat<T> {
       return getTableFormat(name);
     }
   }
+
+  /**
+   * Formats a single {@link org.apache.gravitino.tag.Tag} instance into a 
two-column table display.
+   * Displays tag details including name and comment information.
+   */
+  static final class TagDetailsTableFormat extends TableFormat<Tag> {
+    public TagDetailsTableFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Tag tag) {
+      Column columnName = new Column(context, "name");
+      Column columnComment = new Column(context, "comment");
+
+      columnName.addCell(tag.name());
+      columnComment.addCell(LineUtil.getComment(tag));
+
+      return getTableFormat(columnName, columnComment);
+    }
+  }
+
+  /** Formats an array of {@link org.apache.gravitino.tag.Tag} names into 
table display. */
+  static final class TagListTableFormat extends TableFormat<Tag[]> {
+
+    /**
+     * Creates a new {@link TableFormat} with the specified properties.
+     *
+     * @param context the command context.
+     */
+    public TagListTableFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Tag[] tags) {
+      Column columnName = new Column(context, "name");
+
+      for (Tag t : tags) {
+        columnName.addCell(t.name());
+      }
+
+      return getTableFormat(columnName);
+    }
+  }
+
+  /**
+   * Formats a {@link java.util.Map} which key and value are {@link String} 
into table display.
+   * Lists all key, values in a vertical format.
+   */
+  static final class PropertiesListTableFormat extends TableFormat<Map<?, ?>> {
+
+    /**
+     * Creates a new {@link TableFormat} with the specified properties.
+     *
+     * @param context the command context.
+     */
+    public PropertiesListTableFormat(CommandContext context) {
+      super(context);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String getOutput(Map<?, ?> properties) {
+      Column columnKey = new Column(context, "key");
+      Column columnValue = new Column(context, "value");
+
+      properties.forEach(
+          (key, value) -> {
+            columnKey.addCell(key.toString());
+            columnValue.addCell(value.toString());
+          });
+
+      // if we have empty property, add a placeholder to it.
+      if (properties.isEmpty()) {
+        columnKey.addCell(LineUtil.NULL_DEFAULT_VALUE);
+        columnValue.addCell(LineUtil.NULL_DEFAULT_VALUE);
+      }
+
+      return getTableFormat(columnKey, columnValue);
+    }
+  }
 }
diff --git 
a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java
 
b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java
index c69424e116..7e4309391d 100644
--- 
a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java
+++ 
b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java
@@ -28,6 +28,7 @@ import java.io.PrintStream;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.List;
+import java.util.Map;
 import org.apache.gravitino.Audit;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.Metalake;
@@ -43,11 +44,13 @@ import org.apache.gravitino.rel.expressions.Expression;
 import org.apache.gravitino.rel.expressions.literals.Literal;
 import org.apache.gravitino.rel.types.Type;
 import org.apache.gravitino.rel.types.Types;
+import org.apache.gravitino.tag.Tag;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
 
 public class TestPlainFormat {
 
@@ -256,6 +259,50 @@ public class TestPlainFormat {
         output);
   }
 
+  @Test
+  void testTagDetailsWithPlainFormat() {
+    CommandContext mockContext = getMockContext();
+    Tag mockTag = getMockTag("tag1", "comment for tag1", ImmutableMap.of("k1", 
"v1", "k2", "v2"));
+
+    PlainFormat.output(mockTag, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals("tag1,comment for tag1", output);
+  }
+
+  @Test
+  void testTagDetailsWithPlainFormatWithNullValues() {
+    CommandContext mockContext = getMockContext();
+    Tag mockTag = getMockTag("tag1", null);
+
+    PlainFormat.output(mockTag, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals("tag1,N/A", output);
+  }
+
+  @Test
+  void testListAllTagsWithPlainFormat() {
+    CommandContext mockContext = getMockContext();
+
+    Tag mockTag1 = getMockTag("tag1", "comment for tag1");
+    Tag mockTag2 = getMockTag("tag2", "comment for tag2");
+    Tag mockTag3 = getMockTag("tag3", "comment for tag3");
+
+    PlainFormat.output(new Tag[] {mockTag1, mockTag2, mockTag3}, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals("tag1\n" + "tag2\n" + "tag3", output);
+  }
+
+  @Test
+  void testListTagPropertiesWithPlainFormat() {
+    CommandContext mockContext = getMockContext();
+
+    Tag mockTag1 = getMockTag("tag1", "comment for tag1", 
ImmutableMap.of("k1", "v1", "k2", "v2"));
+
+    PlainFormat.output(mockTag1.properties(), mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals("k1,v1\n" + "k2,v2", output);
+  }
+
   @Test
   void testOutputWithUnsupportType() {
     CommandContext mockContext = getMockContext();
@@ -451,4 +498,17 @@ public class TestPlainFormat {
 
     return mockGroup;
   }
+
+  private Tag getMockTag(String name, String comment) {
+    return getMockTag(name, comment, ImmutableMap.of("k1", "v2", "k2", "v2"));
+  }
+
+  private Tag getMockTag(String name, String comment, Map<String, String> 
properties) {
+    Tag mockTag = mock(Tag.class);
+    when(mockTag.name()).thenReturn(name);
+    when(mockTag.comment()).thenReturn(comment);
+    when(mockTag.properties()).thenReturn(properties);
+
+    return mockTag;
+  }
 }
diff --git 
a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestTableFormat.java
 
b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestTableFormat.java
index 45909b89ce..fe6b97f897 100644
--- 
a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestTableFormat.java
+++ 
b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestTableFormat.java
@@ -30,7 +30,9 @@ import java.io.PrintStream;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import org.apache.gravitino.Audit;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.Metalake;
@@ -47,10 +49,12 @@ import 
org.apache.gravitino.rel.expressions.FunctionExpression;
 import org.apache.gravitino.rel.expressions.literals.Literal;
 import org.apache.gravitino.rel.types.Type;
 import org.apache.gravitino.rel.types.Types;
+import org.apache.gravitino.tag.Tag;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
 
 public class TestTableFormat {
   private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
@@ -672,6 +676,96 @@ public class TestTableFormat {
         output);
   }
 
+  @Test
+  void testTagDetailsWithTableFormat() {
+    CommandContext mockContext = getMockContext();
+    Tag mockTag = getMockTag("tag1", "comment for tag1");
+
+    TableFormat.output(mockTag, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals(
+        "+------+------------------+\n"
+            + "| Name |     Comment      |\n"
+            + "+------+------------------+\n"
+            + "| tag1 | comment for tag1 |\n"
+            + "+------+------------------+",
+        output);
+  }
+
+  @Test
+  void testTagDetailsWithTableFormatWithNullValues() {
+    CommandContext mockContext = getMockContext();
+    Tag mockTag = mock(Tag.class);
+    when(mockTag.name()).thenReturn("tag1");
+    when(mockTag.comment()).thenReturn(null);
+
+    TableFormat.output(mockTag, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals(
+        "+------+---------+\n"
+            + "| Name | Comment |\n"
+            + "+------+---------+\n"
+            + "| tag1 | N/A     |\n"
+            + "+------+---------+",
+        output);
+  }
+
+  @Test
+  void testListAllTagsWithTableFormat() {
+    CommandContext mockContext = getMockContext();
+
+    Tag mockTag1 = getMockTag("tag1", "comment for tag1");
+    Tag mockTag2 = getMockTag("tag2", "comment for tag2");
+    Tag mockTag3 = getMockTag("tag3", "comment for tag3");
+
+    TableFormat.output(new Tag[] {mockTag1, mockTag2, mockTag3}, mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals(
+        "+------+\n"
+            + "| Name |\n"
+            + "+------+\n"
+            + "| tag1 |\n"
+            + "| tag2 |\n"
+            + "| tag3 |\n"
+            + "+------+",
+        output);
+  }
+
+  @Test
+  void testListTagPropertiesWithTableFormat() {
+    CommandContext mockContext = getMockContext();
+
+    Tag mockTag1 = getMockTag("tag1", "comment for tag1");
+
+    TableFormat.output(mockTag1.properties(), mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals(
+        "+-----+-------+\n"
+            + "| Key | Value |\n"
+            + "+-----+-------+\n"
+            + "| k1  | v1    |\n"
+            + "| k2  | v2    |\n"
+            + "+-----+-------+",
+        output);
+  }
+
+  @Test
+  void testListTagPropertiesWithTableFormatWithEmptyMap() {
+    CommandContext mockContext = getMockContext();
+
+    Tag mockTag1 = getMockTag("tag1", "comment for tag1", 
Collections.emptyMap());
+
+    TableFormat.output(mockTag1.properties(), mockContext);
+    String output = new String(outContent.toByteArray(), 
StandardCharsets.UTF_8).trim();
+    Assertions.assertEquals(
+        "+-----+-------+\n"
+            + "| Key | Value |\n"
+            + "+-----+-------+\n"
+            + "| N/A | N/A   |\n"
+            + "+-----+-------+",
+        output);
+  }
+
   @Test
   void testOutputWithUnsupportType() {
     CommandContext mockContext = getMockContext();
@@ -803,4 +897,17 @@ public class TestTableFormat {
 
     return mockGroup;
   }
+
+  private Tag getMockTag(String name, String comment) {
+    return getMockTag(name, comment, ImmutableMap.of("k1", "v1", "k2", "v2"));
+  }
+
+  private Tag getMockTag(String name, String comment, Map<String, String> 
properties) {
+    Tag mockTag = mock(Tag.class);
+    when(mockTag.name()).thenReturn(name);
+    when(mockTag.comment()).thenReturn(comment);
+    when(mockTag.properties()).thenReturn(properties);
+
+    return mockTag;
+  }
 }

Reply via email to