brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.7 KiB · cd52dc8 Raw
186 lines · cpp
1//===-- unittests/Runtime/Format.cpp ----------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CrashHandlerFixture.h"10#include "flang-rt/runtime/connection.h"11#include "flang-rt/runtime/format-implementation.h"12#include "flang-rt/runtime/io-error.h"13#include <optional>14#include <string>15#include <tuple>16#include <vector>17 18using namespace Fortran::runtime;19using namespace Fortran::runtime::io;20using namespace std::literals::string_literals;21 22using ResultsTy = std::vector<std::string>;23 24// A test harness context for testing FormatControl25class TestFormatContext : public IoErrorHandler, public DefinedIoArgs {26public:27  using CharType = char;28  TestFormatContext() : IoErrorHandler{"format.cpp", 1} {}29  bool Emit(const char *, std::size_t, std::size_t = 0);30  bool AdvanceRecord(int = 1);31  void HandleRelativePosition(std::int64_t);32  void HandleAbsolutePosition(std::int64_t);33  void Report(const std::optional<DataEdit> &);34  ResultsTy results;35  MutableModes &mutableModes() { return mutableModes_; }36  ConnectionState &GetConnectionState() { return connectionState_; }37 38private:39  MutableModes mutableModes_;40  ConnectionState connectionState_;41};42 43bool TestFormatContext::Emit(const char *s, std::size_t len, std::size_t) {44  std::string str{s, len};45  results.push_back("'"s + str + '\'');46  return true;47}48 49bool TestFormatContext::AdvanceRecord(int n) {50  while (n-- > 0) {51    results.emplace_back("/");52  }53  return true;54}55 56void TestFormatContext::HandleAbsolutePosition(std::int64_t n) {57  results.push_back("T"s + std::to_string(n));58}59 60void TestFormatContext::HandleRelativePosition(std::int64_t n) {61  if (n < 0) {62    results.push_back("TL"s + std::to_string(-n));63  } else {64    results.push_back(std::to_string(n) + 'X');65  }66}67 68void TestFormatContext::Report(const std::optional<DataEdit> &edit) {69  if (edit) {70    std::string str{edit->descriptor};71    if (edit->repeat != 1) {72      str = std::to_string(edit->repeat) + '*' + str;73    }74    if (edit->variation) {75      str += edit->variation;76    }77    if (edit->width) {78      str += std::to_string(*edit->width);79    }80    if (edit->digits) {81      str += "."s + std::to_string(*edit->digits);82    }83    if (edit->expoDigits) {84      str += "E"s + std::to_string(*edit->expoDigits);85    }86    // modes?87    results.push_back(str);88  } else {89    results.push_back("(nullopt)"s);90  }91}92 93struct FormatTests : public CrashHandlerFixture {};94 95TEST(FormatTests, FormatStringTraversal) {96 97  using ParamsTy = std::tuple<int, const char *, ResultsTy, int>;98 99  static const std::vector<ParamsTy> params{100      {1, "('PI=',F9.7)", ResultsTy{"'PI='", "F9.7"}, 1},101      {1, "(3HPI=F9.7)", ResultsTy{"'PI='", "F9.7"}, 1},102      {1, "(3HPI=/F9.7)", ResultsTy{"'PI='", "/", "F9.7"}, 1},103      {2, "('PI=',F9.7)", ResultsTy{"'PI='", "F9.7", "/", "'PI='", "F9.7"}, 1},104      {2, "(2('PI=',F9.7),'done')",105          ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7", "'done'"}, 1},106      {2, "(3('PI=',F9.7,:),'tooFar')",107          ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7"}, 1},108      {2, "(*('PI=',F9.7,:))", ResultsTy{"'PI='", "F9.7", "'PI='", "F9.7"}, 1},109      {1, "(3F9.7)", ResultsTy{"2*F9.7"}, 2},110      {9, "((I4,2(E10.1)))",111          ResultsTy{"I4", "E10.1", "E10.1", "/", "I4", "E10.1", "E10.1", "/",112              "I4", "E10.1", "E10.1"},113          1},114      {1, "(F)", ResultsTy{"F"}, 1}, // missing 'w'115  };116 117  for (const auto &[n, format, expect, repeat] : params) {118    TestFormatContext context;119    FormatControl<decltype(context)> control{120        context, format, std::strlen(format)};121 122    for (auto i{0}; i < n; i++) {123      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat));124    }125    control.Finish(context);126 127    auto iostat{context.GetIoStat()};128    ASSERT_EQ(iostat, 0) << "Expected iostat == 0, but GetIoStat() == "129                         << iostat;130 131    // Create strings of the expected/actual results for printing errors132    std::string allExpectedResults{""}, allActualResults{""};133    for (const auto &res : context.results) {134      allActualResults += " "s + res;135    }136    for (const auto &res : expect) {137      allExpectedResults += " "s + res;138    }139 140    const auto &results = context.results;141    ASSERT_EQ(expect, results) << "Expected '" << allExpectedResults142                               << "' but got '" << allActualResults << "'";143  }144}145 146struct InvalidFormatFailure : CrashHandlerFixture {};147 148TEST(InvalidFormatFailure, ParenMismatch) {149  static constexpr const char *format{"("};150  static constexpr int repeat{1};151 152  TestFormatContext context;153  FormatControl<decltype(context)> control{154      context, format, std::strlen(format)};155 156  ASSERT_DEATH(157      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),158      R"(FORMAT missing at least one '\)')");159}160 161TEST(InvalidFormatFailure, MissingPrecision) {162  static constexpr const char *format{"(F9.)"};163  static constexpr int repeat{1};164 165  TestFormatContext context;166  FormatControl<decltype(context)> control{167      context, format, std::strlen(format)};168 169  ASSERT_DEATH(170      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),171      R"(Invalid FORMAT: integer expected at '\)')");172}173 174TEST(InvalidFormatFailure, MissingFormatWidthWithDigits) {175  static constexpr const char *format{"(F.9)"};176  static constexpr int repeat{1};177 178  TestFormatContext context;179  FormatControl<decltype(context)> control{180      context, format, std::strlen(format)};181 182  ASSERT_DEATH(183      context.Report(/*edit=*/control.GetNextDataEdit(context, repeat)),184      "Invalid FORMAT: integer expected at '.'");185}186