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

sunchao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new df632c3bd4 test: strengthen ANSI exception assertions (#5800)
df632c3bd4 is described below

commit df632c3bd4a8f098580e98911ce46a92ca122a2c
Author: KUAN-HAO HUANG <[email protected]>
AuthorDate: Thu Sep 10 08:19:52 2026 +0800

    test: strengthen ANSI exception assertions (#5800)
---
 .../apache/comet/CometArrayExpressionSuite.scala   | 32 +++++-------------
 .../org/apache/comet/CometExpressionSuite.scala    | 39 ++++------------------
 .../org/apache/comet/CometNativeCastSuite.scala    | 11 ++----
 .../scala/org/apache/spark/sql/CometTestBase.scala | 27 +++++++++++++++
 4 files changed, 45 insertions(+), 64 deletions(-)

diff --git 
a/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala 
b/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
index 5f769dab9c..ad86dd15bc 100644
--- a/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometArrayExpressionSuite.scala
@@ -1127,15 +1127,9 @@ class CometArrayExpressionSuite extends CometTestBase 
with AdaptiveSparkPlanHelp
         sql("CREATE TABLE test_array_get_item(arr ARRAY<INT>) USING parquet")
         sql("INSERT INTO test_array_get_item VALUES (array(1, 2, 3))")
         // Try to access array with out-of-bounds index
-        val exception = intercept[Exception] {
-          sql("select arr[5] from test_array_get_item").collect()
-        }
+        val exception =
+          checkSparkError(sql("select arr[5] from test_array_get_item"), 
"INVALID_ARRAY_INDEX")
         val errorMessage = exception.getMessage
-        // Verify error message contains the expected error code
-        assert(
-          errorMessage.contains("INVALID_ARRAY_INDEX"),
-          s"Error message should contain array index error: $errorMessage")
-
         assert(errorMessage.contains("The index 5 is out of bounds. The array 
has 3 elements." +
           " Use the SQL function `get()` to tolerate accessing element at 
invalid index and return NULL instead."))
 
@@ -1156,15 +1150,10 @@ class CometArrayExpressionSuite extends CometTestBase 
with AdaptiveSparkPlanHelp
         sql("CREATE TABLE test_element_at_invalid(arr ARRAY<INT>) USING 
parquet")
         sql("INSERT INTO test_element_at_invalid VALUES (array(1, 2, 3))")
         // Try to access array with out-of-bounds index using element_at
-        val exception = intercept[Exception] {
-          sql("select element_at(arr, 10) from 
test_element_at_invalid").collect()
-        }
+        val exception = checkSparkError(
+          sql("select element_at(arr, 10) from test_element_at_invalid"),
+          "INVALID_ARRAY_INDEX_IN_ELEMENT_AT")
         val errorMessage = exception.getMessage
-        // Verify error message contains the expected error code
-        assert(
-          errorMessage.contains("INVALID_ARRAY_INDEX_IN_ELEMENT_AT"),
-          s"Error message should contain array index error: $errorMessage")
-
         assert(errorMessage.contains("The index 10 is out of bounds. The array 
has 3 elements." +
           " Use `try_element_at` to tolerate accessing element at invalid 
index and return NULL instead"))
 
@@ -1185,15 +1174,10 @@ class CometArrayExpressionSuite extends CometTestBase 
with AdaptiveSparkPlanHelp
         sql("CREATE TABLE test_element_at_zero(arr ARRAY<INT>) USING parquet")
         sql("INSERT INTO test_element_at_zero VALUES (array(1, 2, 3))")
         // Try to access array with zero index (invalid in Spark)
-        val exception = intercept[Exception] {
-          sql("select element_at(arr, 0) from test_element_at_zero").collect()
-        }
+        val exception = checkSparkError(
+          sql("select element_at(arr, 0) from test_element_at_zero"),
+          "INVALID_INDEX_OF_ZERO")
         val errorMessage = exception.getMessage
-        // Verify error message contains the expected error code
-        assert(
-          errorMessage.contains("INVALID_INDEX_OF_ZERO"),
-          s"Error message should contain zero index error: $errorMessage")
-
         assert(
           errorMessage.contains("The index 0 is invalid. An index shall be 
either < 0 or > 0" +
             " (the first element has index 1)"))
diff --git a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala 
b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
index 25b43d9fe6..4ab86b4f37 100644
--- a/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala
@@ -39,8 +39,6 @@ import org.apache.comet.testing.{DataGenOptions, 
FuzzDataGenerator}
 class CometExpressionSuite extends CometTestBase with AdaptiveSparkPlanHelper {
   import testImplicits._
 
-  val ARITHMETIC_OVERFLOW_EXCEPTION_MSG =
-    """[ARITHMETIC_OVERFLOW] integer overflow. If necessary set 
"spark.sql.ansi.enabled" to "false" to bypass this error"""
   val DIVIDE_BY_ZERO_EXCEPTION_MSG =
     """Division by zero. Use `try_divide` to tolerate divisor being 0 and 
return NULL instead"""
 
@@ -2944,12 +2942,7 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                               |  from tbl
                               |  """.stripMargin)
 
-        checkSparkAnswerMaybeThrows(res) match {
-          case (Some(sparkExc), Some(cometExc)) =>
-            
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
-            assert(sparkExc.getMessage.contains("overflow"))
-          case _ => fail("Exception should be thrown")
-        }
+        checkSparkError(res, "ARITHMETIC_OVERFLOW")
       }
     }
   }
@@ -2964,12 +2957,7 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                               |  _1 - _2
                               |  from tbl
                               |  """.stripMargin)
-        checkSparkAnswerMaybeThrows(res) match {
-          case (Some(sparkExc), Some(cometExc)) =>
-            
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
-            assert(sparkExc.getMessage.contains("overflow"))
-          case _ => fail("Exception should be thrown")
-        }
+        checkSparkError(res, "ARITHMETIC_OVERFLOW")
       }
     }
   }
@@ -2985,12 +2973,7 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                               |  from tbl
                               |  """.stripMargin)
 
-        checkSparkAnswerMaybeThrows(res) match {
-          case (Some(sparkExc), Some(cometExc)) =>
-            
assert(cometExc.getMessage.contains(ARITHMETIC_OVERFLOW_EXCEPTION_MSG))
-            assert(sparkExc.getMessage.contains("overflow"))
-          case _ => fail("Exception should be thrown")
-        }
+        checkSparkError(res, "ARITHMETIC_OVERFLOW")
       }
     }
   }
@@ -3005,12 +2988,7 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                               |  from tbl
                               |  """.stripMargin)
 
-        checkSparkAnswerMaybeThrows(res) match {
-          case (Some(sparkExc), Some(cometExc)) =>
-            assert(cometExc.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
-            assert(sparkExc.getMessage.contains("Division by zero"))
-          case _ => fail("Exception should be thrown")
-        }
+        checkSparkError(res, "DIVIDE_BY_ZERO")
       }
     }
   }
@@ -3025,12 +3003,7 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                               |  from tbl
                               |  """.stripMargin)
 
-        checkSparkAnswerMaybeThrows(res) match {
-          case (Some(sparkExc), Some(cometExc)) =>
-            assert(cometExc.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
-            assert(sparkExc.getMessage.contains("Division by zero"))
-          case _ => fail("Exception should be thrown")
-        }
+        checkSparkError(res, "DIVIDE_BY_ZERO")
       }
     }
   }
@@ -3046,6 +3019,8 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
                 |  from tbl
                 |  """.stripMargin)
 
+          // Integral divide still raises an unconverted Arrow error under 
ANSI.
+          // https://github.com/apache/datafusion-comet/issues/5072
           checkSparkAnswerMaybeThrows(res) match {
             case (Some(sparkException), Some(cometException)) =>
               
assert(sparkException.getMessage.contains(DIVIDE_BY_ZERO_EXCEPTION_MSG))
diff --git a/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala 
b/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
index 2a2854ece3..e96367bfe5 100644
--- a/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
+++ b/spark/src/test/scala/org/apache/comet/CometNativeCastSuite.scala
@@ -1382,15 +1382,9 @@ class CometNativeCastSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
         // Create a table with string data using DataFrame API
         
Seq("a").toDF("s").write.format("parquet").saveAsTable("cast_error_msg")
         // Try to cast invalid string to date - should throw exception with 
SQL context
-        val exception = intercept[Exception] {
-          sql("select cast(s as date) from cast_error_msg").collect()
-        }
+        val exception =
+          checkSparkError(sql("select cast(s as date) from cast_error_msg"), 
"CAST_INVALID_INPUT")
         val errorMessage = exception.getMessage
-        // Verify error message contains the cast invalid input error
-        assert(
-          errorMessage.contains("CAST_INVALID_INPUT") ||
-            errorMessage.contains("cannot be cast to"),
-          s"Error message should contain cast error: $errorMessage")
 
         assert(
           errorMessage.contains("select cast(s as date) from cast_error_msg"),
@@ -2873,6 +2867,7 @@ class CometNativeCastSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
               val cometMessage =
                 if (cometException.getCause != null) 
cometException.getCause.getMessage
                 else cometException.getMessage
+              // https://github.com/apache/datafusion-comet/issues/5072
               // this if branch should only check decimal to decimal cast and 
errors when output precision, scale causes overflow.
               if (df.schema("a").dataType.typeName.contains("decimal") && 
toType.typeName
                   .contains("decimal") && sparkMessage.contains("cannot be 
represented as")) {
diff --git a/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala 
b/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
index 975ba509cc..39a2044b20 100644
--- a/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
+++ b/spark/src/test/scala/org/apache/spark/sql/CometTestBase.scala
@@ -366,6 +366,33 @@ abstract class CometTestBase
     }
   }
 
+  /** Checks native execution and Spark exception type, error class and 
SQLSTATE parity. */
+  protected def checkSparkError(
+      df: DataFrame,
+      errorClass: String): SparkThrowable with Throwable = {
+    checkCometOperators(stripAQEPlan(df.queryExecution.executedPlan))
+    val (sparkError, cometError) = checkSparkAnswerMaybeThrows(df)
+
+    def structuredError(
+        error: Option[Throwable],
+        engine: String): SparkThrowable with Throwable = {
+      val failure = error.getOrElse(fail(s"$engine did not fail with 
$errorClass"))
+      val chain = causeChain(failure)
+      assert(!chain.exists(_.isInstanceOf[CometNativeException]), s"$engine: 
$failure")
+      chain.collect { case e: SparkThrowable with Throwable => e 
}.lastOption.getOrElse {
+        fail(s"$engine did not throw a SparkThrowable: $failure")
+      }
+    }
+
+    val expected = structuredError(sparkError, "Spark")
+    val actual = structuredError(cometError, "Comet")
+    assert(expected.getErrorClass == errorClass)
+    assert(actual.getClass == expected.getClass)
+    assert(actual.getErrorClass == errorClass)
+    assert(actual.getSqlState == expected.getSqlState)
+    actual
+  }
+
   /**
    * Compares the Comet DataFrame result against the expected Spark answer, 
using labels that
    * correctly identify which side is Comet and which is Spark. This avoids 
the misleading "Spark


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to