Add unit tests for 4x4 ADST

Enable sign bias check and round-trip error unit tests for 4x4 hybrid
transform modules.

Change-Id: Icd3d839f098d4b92b00ff76eac146765b039d0d3
diff --git a/test/fdct4x4_test.cc b/test/fdct4x4_test.cc
index 1c887bb..e246491 100644
--- a/test/fdct4x4_test.cc
+++ b/test/fdct4x4_test.cc
@@ -24,8 +24,56 @@
 using libvpx_test::ACMRandom;
 
 namespace {
+void fdct4x4(int16_t *in, int16_t *out, uint8_t *dst, int stride, int tx_type) {
+  vp9_short_fdct4x4_c(in, out, stride);
+}
+void idct4x4_add(int16_t *in, int16_t *out, uint8_t *dst,
+                 int stride, int tx_type) {
+  vp9_short_idct4x4_add_c(out, dst, stride >> 1);
+}
+void fht4x4(int16_t *in, int16_t *out, uint8_t *dst, int stride, int tx_type) {
+  vp9_short_fht4x4_c(in, out, stride >> 1, tx_type);
+}
+void iht4x4_add(int16_t *in, int16_t *out, uint8_t *dst,
+                int stride, int tx_type) {
+  vp9_short_iht4x4_add_c(out, dst, stride >> 1, tx_type);
+}
 
-TEST(Vp9Fdct4x4Test, SignBiasCheck) {
+class FwdTrans4x4Test : public ::testing::TestWithParam<int> {
+ public:
+  FwdTrans4x4Test() {SetUpTestTxfm();}
+  ~FwdTrans4x4Test() {}
+
+  void SetUpTestTxfm() {
+    tx_type = GetParam();
+    if (tx_type == 0) {
+      fwd_txfm = fdct4x4;
+      inv_txfm = idct4x4_add;
+    } else {
+      fwd_txfm = fht4x4;
+      inv_txfm = iht4x4_add;
+    }
+  }
+
+ protected:
+  void RunFwdTxfm(int16_t *in, int16_t *out, uint8_t *dst,
+                  int stride, int tx_type) {
+    (*fwd_txfm)(in, out, dst, stride, tx_type);
+  }
+
+  void RunInvTxfm(int16_t *in, int16_t *out, uint8_t *dst,
+                  int stride, int tx_type) {
+    (*inv_txfm)(in, out, dst, stride, tx_type);
+  }
+
+  int tx_type;
+  void (*fwd_txfm)(int16_t *in, int16_t *out, uint8_t *dst,
+                   int stride, int tx_type);
+  void (*inv_txfm)(int16_t *in, int16_t *out, uint8_t *dst,
+                   int stride, int tx_type);
+};
+
+TEST_P(FwdTrans4x4Test, SignBiasCheck) {
   ACMRandom rnd(ACMRandom::DeterministicSeed());
   int16_t test_input_block[16];
   int16_t test_output_block[16];
@@ -34,15 +82,12 @@
   const int count_test_block = 1000000;
 
   memset(count_sign_block, 0, sizeof(count_sign_block));
-
   for (int i = 0; i < count_test_block; ++i) {
     // Initialize a test block with input range [-255, 255].
     for (int j = 0; j < 16; ++j)
       test_input_block[j] = rnd.Rand8() - rnd.Rand8();
 
-    // TODO(Yaowu): this should be converted to a parameterized test
-    // to test optimized versions of this function.
-    vp9_short_fdct4x4_c(test_input_block, test_output_block, pitch);
+    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type);
 
     for (int j = 0; j < 16; ++j) {
       if (test_output_block[j] < 0)
@@ -56,20 +101,18 @@
     const bool bias_acceptable = (abs(count_sign_block[j][0] -
                                       count_sign_block[j][1]) < 10000);
     EXPECT_TRUE(bias_acceptable)
-        << "Error: 4x4 FDCT has a sign bias > 1%"
-        << " for input range [-255, 255] at index " << j;
+        << "Error: 4x4 FDCT/FHT has a sign bias > 1%"
+        << " for input range [-255, 255] at index " << j
+        << " tx_type " << tx_type;
   }
 
   memset(count_sign_block, 0, sizeof(count_sign_block));
-
   for (int i = 0; i < count_test_block; ++i) {
     // Initialize a test block with input range [-15, 15].
     for (int j = 0; j < 16; ++j)
       test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);
 
-    // TODO(Yaowu): this should be converted to a parameterized test
-    // to test optimized versions of this function.
-    vp9_short_fdct4x4_c(test_input_block, test_output_block, pitch);
+    RunFwdTxfm(test_input_block, test_output_block, NULL, pitch, tx_type);
 
     for (int j = 0; j < 16; ++j) {
       if (test_output_block[j] < 0)
@@ -83,13 +126,14 @@
     const bool bias_acceptable = (abs(count_sign_block[j][0] -
                                       count_sign_block[j][1]) < 100000);
     EXPECT_TRUE(bias_acceptable)
-        << "Error: 4x4 FDCT has a sign bias > 10%"
+        << "Error: 4x4 FDCT/FHT has a sign bias > 10%"
         << " for input range [-15, 15] at index " << j;
   }
-};
+}
 
-TEST(Vp9Fdct4x4Test, RoundTripErrorCheck) {
+TEST_P(FwdTrans4x4Test, RoundTripErrorCheck) {
   ACMRandom rnd(ACMRandom::DeterministicSeed());
+
   int max_error = 0;
   double total_error = 0;
   const int count_test_block = 1000000;
@@ -106,10 +150,8 @@
     for (int j = 0; j < 16; ++j)
       test_input_block[j] = src[j] - dst[j];
 
-    // TODO(Yaowu): this should be converted to a parameterized test
-    // to test optimized versions of this function.
     const int pitch = 8;
-    vp9_short_fdct4x4_c(test_input_block, test_temp_block, pitch);
+    RunFwdTxfm(test_input_block, test_temp_block, dst, pitch, tx_type);
 
     for (int j = 0; j < 16; ++j) {
         if(test_temp_block[j] > 0) {
@@ -123,8 +165,8 @@
         }
     }
 
-    // Because the bitstream is not frozen yet, use the idct in the codebase.
-    vp9_short_idct4x4_add_c(test_temp_block, dst, 4);
+    // inverse transform and reconstruct the pixel block
+    RunInvTxfm(test_input_block, test_temp_block, dst, pitch, tx_type);
 
     for (int j = 0; j < 16; ++j) {
       const int diff = dst[j] - src[j];
@@ -135,10 +177,12 @@
     }
   }
   EXPECT_GE(1, max_error)
-      << "Error: FDCT/IDCT has an individual roundtrip error > 1";
+      << "Error: FDCT/IDCT or FHT/IHT has an individual roundtrip error > 1";
 
   EXPECT_GE(count_test_block, total_error)
-      << "Error: FDCT/IDCT has average roundtrip error > 1 per block";
-};
+      << "Error: FDCT/IDCT or FHT/IHT has average "
+          "roundtrip error > 1 per block";
+}
 
+INSTANTIATE_TEST_CASE_P(VP9, FwdTrans4x4Test, ::testing::Range(0, 4));
 }  // namespace