[flang-commits] [flang] 4abba77 - [flang] Add format test to GTest suite

Asher Mancinelli via flang-commits flang-commits at lists.llvm.org
Tue Apr 27 07:45:55 PDT 2021


Author: Asher Mancinelli
Date: 2021-04-27T07:45:18-07:00
New Revision: 4abba775a39af7f5be5d4573011930b639d69b63

URL: https://github.com/llvm/llvm-project/commit/4abba775a39af7f5be5d4573011930b639d69b63
DIFF: https://github.com/llvm/llvm-project/commit/4abba775a39af7f5be5d4573011930b639d69b63.diff

LOG: [flang] Add format test to GTest suite

Reviewed by: awarzynski
Differential Revision: https://reviews.llvm.org/D100765

Added: 
    flang/unittests/RuntimeGTest/Format.cpp

Modified: 
    flang/unittests/Runtime/CMakeLists.txt
    flang/unittests/RuntimeGTest/CMakeLists.txt

Removed: 
    flang/unittests/Runtime/format.cpp


################################################################################
diff  --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt
index 03998fa55d14..2459aed47bb7 100644
--- a/flang/unittests/Runtime/CMakeLists.txt
+++ b/flang/unittests/Runtime/CMakeLists.txt
@@ -18,11 +18,6 @@ target_link_libraries(RuntimeTesting
   ${llvm_libs}
 )
 
-add_flang_nongtest_unittest(format
-  RuntimeTesting
-  FortranRuntime
-)
-
 # This test is not run by default as it requires input.
 add_executable(external-hello-world
   external-hello.cpp

diff  --git a/flang/unittests/Runtime/format.cpp b/flang/unittests/Runtime/format.cpp
deleted file mode 100644
index 87989eacebcb..000000000000
--- a/flang/unittests/Runtime/format.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// Tests basic FORMAT string traversal
-
-#include "testing.h"
-#include "../runtime/format-implementation.h"
-#include "../runtime/io-error.h"
-#include <cstdarg>
-#include <cstring>
-#include <string>
-#include <vector>
-
-using namespace Fortran::runtime;
-using namespace Fortran::runtime::io;
-using namespace std::literals::string_literals;
-
-using Results = std::vector<std::string>;
-
-// A test harness context for testing FormatControl
-class TestFormatContext : public IoErrorHandler {
-public:
-  using CharType = char;
-  TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}
-  bool Emit(const char *, std::size_t);
-  bool Emit(const char16_t *, std::size_t);
-  bool Emit(const char32_t *, std::size_t);
-  bool AdvanceRecord(int = 1);
-  void HandleRelativePosition(std::int64_t);
-  void HandleAbsolutePosition(std::int64_t);
-  void Report(const DataEdit &);
-  void Check(Results &);
-  Results results;
-  MutableModes &mutableModes() { return mutableModes_; }
-
-private:
-  MutableModes mutableModes_;
-};
-
-bool TestFormatContext::Emit(const char *s, std::size_t len) {
-  std::string str{s, len};
-  results.push_back("'"s + str + '\'');
-  return true;
-}
-bool TestFormatContext::Emit(const char16_t *, std::size_t) {
-  Crash("TestFormatContext::Emit(const char16_t *) called");
-  return false;
-}
-bool TestFormatContext::Emit(const char32_t *, std::size_t) {
-  Crash("TestFormatContext::Emit(const char32_t *) called");
-  return false;
-}
-
-bool TestFormatContext::AdvanceRecord(int n) {
-  while (n-- > 0) {
-    results.emplace_back("/");
-  }
-  return true;
-}
-
-void TestFormatContext::HandleAbsolutePosition(std::int64_t n) {
-  results.push_back("T"s + std::to_string(n));
-}
-
-void TestFormatContext::HandleRelativePosition(std::int64_t n) {
-  if (n < 0) {
-    results.push_back("TL"s + std::to_string(-n));
-  } else {
-    results.push_back(std::to_string(n) + 'X');
-  }
-}
-
-void TestFormatContext::Report(const DataEdit &edit) {
-  std::string str{edit.descriptor};
-  if (edit.repeat != 1) {
-    str = std::to_string(edit.repeat) + '*' + str;
-  }
-  if (edit.variation) {
-    str += edit.variation;
-  }
-  if (edit.width) {
-    str += std::to_string(*edit.width);
-  }
-  if (edit.digits) {
-    str += "."s + std::to_string(*edit.digits);
-  }
-  if (edit.expoDigits) {
-    str += "E"s + std::to_string(*edit.expoDigits);
-  }
-  // modes?
-  results.push_back(str);
-}
-
-void TestFormatContext::Check(Results &expect) {
-  if (expect != results) {
-    Fail() << "expected:";
-    for (const std::string &s : expect) {
-      llvm::errs() << ' ' << s;
-    }
-    llvm::errs() << "\ngot:";
-    for (const std::string &s : results) {
-      llvm::errs() << ' ' << s;
-    }
-    llvm::errs() << '\n';
-  }
-  expect.clear();
-  results.clear();
-}
-
-static void Test(int n, const char *format, Results &&expect, int repeat = 1) {
-  TestFormatContext context;
-  FormatControl<TestFormatContext> control{
-      context, format, std::strlen(format)};
-  try {
-    for (int j{0}; j < n; ++j) {
-      context.Report(control.GetNextDataEdit(context, repeat));
-    }
-    control.Finish(context);
-    if (int iostat{context.GetIoStat()}) {
-      context.Crash("GetIoStat() == %d", iostat);
-    }
-  } catch (const std::string &crash) {
-    context.results.push_back("Crash:"s + crash);
-  }
-  context.Check(expect);
-}
-
-int main() {
-  StartTests();
-  Test(1, "('PI=',F9.7)", Results{"'PI='", "F9.7"});
-  Test(1, "(3HPI=F9.7)", Results{"'PI='", "F9.7"});
-  Test(1, "(3HPI=/F9.7)", Results{"'PI='", "/", "F9.7"});
-  Test(2, "('PI=',F9.7)", Results{"'PI='", "F9.7", "/", "'PI='", "F9.7"});
-  Test(2, "(2('PI=',F9.7),'done')",
-      Results{"'PI='", "F9.7", "'PI='", "F9.7", "'done'"});
-  Test(2, "(3('PI=',F9.7,:),'tooFar')",
-      Results{"'PI='", "F9.7", "'PI='", "F9.7"});
-  Test(2, "(*('PI=',F9.7,:),'tooFar')",
-      Results{"'PI='", "F9.7", "'PI='", "F9.7"});
-  Test(1, "(3F9.7)", Results{"2*F9.7"}, 2);
-  return EndTests();
-}

diff  --git a/flang/unittests/RuntimeGTest/CMakeLists.txt b/flang/unittests/RuntimeGTest/CMakeLists.txt
index 38a577d5add0..cc29f31c829d 100644
--- a/flang/unittests/RuntimeGTest/CMakeLists.txt
+++ b/flang/unittests/RuntimeGTest/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_flang_unittest(FlangRuntimeTests
   CharacterTest.cpp
   CrashHandlerFixture.cpp
+  Format.cpp
   MiscIntrinsic.cpp
   Numeric.cpp
   NumericalFormatTest.cpp

diff  --git a/flang/unittests/RuntimeGTest/Format.cpp b/flang/unittests/RuntimeGTest/Format.cpp
new file mode 100644
index 000000000000..63a1801071b4
--- /dev/null
+++ b/flang/unittests/RuntimeGTest/Format.cpp
@@ -0,0 +1,183 @@
+//===-- flang/unittests/RuntimeGTest/Format.cpp -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrashHandlerFixture.h"
+#include "../runtime/format-implementation.h"
+#include "../runtime/io-error.h"
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace Fortran::runtime;
+using namespace Fortran::runtime::io;
+using namespace std::literals::string_literals;
+
+using ResultsTy = std::vector<std::string>;
+
+// A test harness context for testing FormatControl
+class TestFormatContext : public IoErrorHandler {
+public:
+  using CharType = char;
+  TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}
+  bool Emit(const char *, std::size_t);
+  bool Emit(const char16_t *, std::size_t);
+  bool Emit(const char32_t *, std::size_t);
+  bool AdvanceRecord(int = 1);
+  void HandleRelativePosition(std::int64_t);
+  void HandleAbsolutePosition(std::int64_t);
+  void Report(const DataEdit &);
+  ResultsTy results;
+  MutableModes &mutableModes() { return mutableModes_; }
+
+private:
+  MutableModes mutableModes_;
+};
+
+bool TestFormatContext::Emit(const char *s, std::size_t len) {
+  std::string str{s, len};
+  results.push_back("'"s + str + '\'');
+  return true;
+}
+bool TestFormatContext::Emit(const char16_t *, std::size_t) {
+  Crash("TestFormatContext::Emit(const char16_t *) called");
+  return false;
+}
+bool TestFormatContext::Emit(const char32_t *, std::size_t) {
+  Crash("TestFormatContext::Emit(const char32_t *) called");
+  return false;
+}
+
+bool TestFormatContext::AdvanceRecord(int n) {
+  while (n-- > 0) {
+    results.emplace_back("/");
+  }
+  return true;
+}
+
+void TestFormatContext::HandleAbsolutePosition(std::int64_t n) {
+  results.push_back("T"s + std::to_string(n));
+}
+
+void TestFormatContext::HandleRelativePosition(std::int64_t n) {
+  if (n < 0) {
+    results.push_back("TL"s + std::to_string(-n));
+  } else {
+    results.push_back(std::to_string(n) + 'X');
+  }
+}
+
+void TestFormatContext::Report(const DataEdit &edit) {
+  std::string str{edit.descriptor};
+  if (edit.repeat != 1) {
+    str = std::to_string(edit.repeat) + '*' + str;
+  }
+  if (edit.variation) {
+    str += edit.variation;
+  }
+  if (edit.width) {
+    str += std::to_string(*edit.width);
+  }
+  if (edit.digits) {
+    str += "."s + std::to_string(*edit.digits);
+  }
+  if (edit.expoDigits) {
+    str += "E"s + std::to_string(*edit.expoDigits);
+  }
+  // modes?
+  results.push_back(str);
+}
+
+struct FormatTests : public CrashHandlerFixture {};
+
+TEST(FormatTests, FormatStringTraversal) {
+
+  using ParamsTy = std::tuple<int, const char *, ResultsTy, int>;
+
+  static const std::vector<ParamsTy> params{
+      {1, "('PI=',F9.7)", ResultsTy{"'PI='", "F9.7"}, 1},
+      {1, "(3HPI=F9.7)", ResultsTy{"'PI='", "F9.7"}, 1},
+      {1, "(3HPI=/F9.7)", ResultsTy{"'PI='", "/", "F9.7"}, 1},
+      {2, "('PI=',F9.7)", ResultsTy{"'PI='", "F9.7", "/", "'PI='", "F9.7"}, 1},
+      {2, "(2('PI=',F9.7),'done')",
+          ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7", "'done'"}, 1},
+      {2, "(3('PI=',F9.7,:),'tooFar')",
+          ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7"}, 1},
+      {2, "(*('PI=',F9.7,:),'tooFar')",
+          ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7"}, 1},
+      {1, "(3F9.7)", ResultsTy{"2*F9.7"}, 2},
+  };
+
+  for (const auto &[n, format, expect, repeat] : params) {
+    TestFormatContext context;
+    FormatControl<decltype(context)> control{
+        context, format, std::strlen(format)};
+
+    for (auto i{0}; i < n; i++) {
+      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat));
+    }
+    control.Finish(context);
+
+    auto iostat{context.GetIoStat()};
+    ASSERT_EQ(iostat, 0) << "Expected iostat == 0, but GetIoStat() == "
+                         << iostat;
+
+    // Create strings of the expected/actual results for printing errors
+    std::string allExpectedResults{""}, allActualResults{""};
+    for (const auto &res : context.results) {
+      allActualResults += " "s + res;
+    }
+    for (const auto &res : expect) {
+      allExpectedResults += " "s + res;
+    }
+
+    const auto &results = context.results;
+    ASSERT_EQ(expect, results) << "Expected '" << allExpectedResults
+                               << "' but got '" << allActualResults << "'";
+  }
+}
+
+struct InvalidFormatFailure : CrashHandlerFixture {};
+
+TEST(InvalidFormatFailure, ParenMismatch) {
+  static constexpr const char *format{"("};
+  static constexpr int repeat{1};
+
+  TestFormatContext context;
+  FormatControl<decltype(context)> control{
+      context, format, std::strlen(format)};
+
+  ASSERT_DEATH(
+      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),
+      "FORMAT missing at least one ')'");
+}
+
+TEST(InvalidFormatFailure, MissingPrecision) {
+  static constexpr const char *format{"(F9.)"};
+  static constexpr int repeat{1};
+
+  TestFormatContext context;
+  FormatControl<decltype(context)> control{
+      context, format, std::strlen(format)};
+
+  ASSERT_DEATH(
+      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),
+      "Invalid FORMAT: integer expected at ')'");
+}
+
+TEST(InvalidFormatFailure, MissingFormatWidth) {
+  static constexpr const char *format{"(F.9)"};
+  static constexpr int repeat{1};
+
+  TestFormatContext context;
+  FormatControl<decltype(context)> control{
+      context, format, std::strlen(format)};
+
+  ASSERT_DEATH(
+      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),
+      "Invalid FORMAT: integer expected at '.'");
+}


        


More information about the flang-commits mailing list