summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/Support/YAMLIOTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/Support/YAMLIOTest.cpp')
-rw-r--r--llvm/unittests/Support/YAMLIOTest.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp
index 94e9874147f..17f38f9b86c 100644
--- a/llvm/unittests/Support/YAMLIOTest.cpp
+++ b/llvm/unittests/Support/YAMLIOTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
@@ -2642,3 +2643,235 @@ TEST(YAMLIO, Numeric) {
EXPECT_FALSE(isNumeric("-inf"));
EXPECT_FALSE(isNumeric("1,230.15"));
}
+
+//===----------------------------------------------------------------------===//
+// Test PolymorphicTraits and TaggedScalarTraits
+//===----------------------------------------------------------------------===//
+
+struct Poly {
+ enum NodeKind {
+ NK_Scalar,
+ NK_Seq,
+ NK_Map,
+ } Kind;
+
+ Poly(NodeKind Kind) : Kind(Kind) {}
+
+ virtual ~Poly() = default;
+
+ NodeKind getKind() const { return Kind; }
+};
+
+struct Scalar : Poly {
+ enum ScalarKind {
+ SK_Unknown,
+ SK_Double,
+ SK_Bool,
+ } SKind;
+
+ union {
+ double DoubleValue;
+ bool BoolValue;
+ };
+
+ Scalar() : Poly(NK_Scalar), SKind(SK_Unknown) {}
+ Scalar(double DoubleValue)
+ : Poly(NK_Scalar), SKind(SK_Double), DoubleValue(DoubleValue) {}
+ Scalar(bool BoolValue)
+ : Poly(NK_Scalar), SKind(SK_Bool), BoolValue(BoolValue) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Scalar; }
+};
+
+struct Seq : Poly, std::vector<std::unique_ptr<Poly>> {
+ Seq() : Poly(NK_Seq) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Seq; }
+};
+
+struct Map : Poly, llvm::StringMap<std::unique_ptr<Poly>> {
+ Map() : Poly(NK_Map) {}
+
+ static bool classof(const Poly *N) { return N->getKind() == NK_Map; }
+};
+
+namespace llvm {
+namespace yaml {
+
+template <> struct PolymorphicTraits<std::unique_ptr<Poly>> {
+ static NodeKind getKind(const std::unique_ptr<Poly> &N) {
+ if (isa<Scalar>(*N))
+ return NodeKind::Scalar;
+ if (isa<Seq>(*N))
+ return NodeKind::Sequence;
+ if (isa<Map>(*N))
+ return NodeKind::Map;
+ llvm_unreachable("unsupported node type");
+ }
+
+ static Scalar &getAsScalar(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Scalar>(*N))
+ N = llvm::make_unique<Scalar>();
+ return *cast<Scalar>(N.get());
+ }
+
+ static Seq &getAsSequence(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Seq>(*N))
+ N = llvm::make_unique<Seq>();
+ return *cast<Seq>(N.get());
+ }
+
+ static Map &getAsMap(std::unique_ptr<Poly> &N) {
+ if (!N || !isa<Map>(*N))
+ N = llvm::make_unique<Map>();
+ return *cast<Map>(N.get());
+ }
+};
+
+template <> struct TaggedScalarTraits<Scalar> {
+ static void output(const Scalar &S, void *Ctxt, raw_ostream &ScalarOS,
+ raw_ostream &TagOS) {
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ report_fatal_error("output unknown scalar");
+ break;
+ case Scalar::SK_Double:
+ TagOS << "!double";
+ ScalarTraits<double>::output(S.DoubleValue, Ctxt, ScalarOS);
+ break;
+ case Scalar::SK_Bool:
+ TagOS << "!bool";
+ ScalarTraits<bool>::output(S.BoolValue, Ctxt, ScalarOS);
+ break;
+ }
+ }
+
+ static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt,
+ Scalar &S) {
+ S.SKind = StringSwitch<Scalar::ScalarKind>(Tag)
+ .Case("!double", Scalar::SK_Double)
+ .Case("!bool", Scalar::SK_Bool)
+ .Default(Scalar::SK_Unknown);
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ return StringRef("unknown scalar tag");
+ case Scalar::SK_Double:
+ return ScalarTraits<double>::input(ScalarStr, Ctxt, S.DoubleValue);
+ case Scalar::SK_Bool:
+ return ScalarTraits<bool>::input(ScalarStr, Ctxt, S.BoolValue);
+ }
+ llvm_unreachable("unknown scalar kind");
+ }
+
+ static QuotingType mustQuote(const Scalar &S, StringRef Str) {
+ switch (S.SKind) {
+ case Scalar::SK_Unknown:
+ report_fatal_error("quote unknown scalar");
+ case Scalar::SK_Double:
+ return ScalarTraits<double>::mustQuote(Str);
+ case Scalar::SK_Bool:
+ return ScalarTraits<bool>::mustQuote(Str);
+ }
+ llvm_unreachable("unknown scalar kind");
+ }
+};
+
+template <> struct CustomMappingTraits<Map> {
+ static void inputOne(IO &IO, StringRef Key, Map &M) {
+ IO.mapRequired(Key.str().c_str(), M[Key]);
+ }
+
+ static void output(IO &IO, Map &M) {
+ for (auto &N : M)
+ IO.mapRequired(N.getKey().str().c_str(), N.getValue());
+ }
+};
+
+template <> struct SequenceTraits<Seq> {
+ static size_t size(IO &IO, Seq &A) { return A.size(); }
+
+ static std::unique_ptr<Poly> &element(IO &IO, Seq &A, size_t Index) {
+ if (Index >= A.size())
+ A.resize(Index + 1);
+ return A[Index];
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+TEST(YAMLIO, TestReadWritePolymorphicScalar) {
+ std::string intermediate;
+ std::unique_ptr<Poly> node = llvm::make_unique<Scalar>(true);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+#ifdef GTEST_HAS_DEATH_TEST
+#ifndef NDEBUG
+ EXPECT_DEATH(yout << node, "plain scalar documents are not supported");
+#endif
+#endif
+}
+
+TEST(YAMLIO, TestReadWritePolymorphicSeq) {
+ std::string intermediate;
+ {
+ auto seq = llvm::make_unique<Seq>();
+ seq->push_back(llvm::make_unique<Scalar>(true));
+ seq->push_back(llvm::make_unique<Scalar>(1.0));
+ auto node = llvm::unique_dyn_cast<Poly>(seq);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << node;
+ }
+ {
+ Input yin(intermediate);
+ std::unique_ptr<Poly> node;
+ yin >> node;
+
+ EXPECT_FALSE(yin.error());
+ auto seq = llvm::dyn_cast<Seq>(node.get());
+ ASSERT_TRUE(seq);
+ ASSERT_EQ(seq->size(), 2u);
+ auto first = llvm::dyn_cast<Scalar>((*seq)[0].get());
+ ASSERT_TRUE(first);
+ EXPECT_EQ(first->SKind, Scalar::SK_Bool);
+ EXPECT_TRUE(first->BoolValue);
+ auto second = llvm::dyn_cast<Scalar>((*seq)[1].get());
+ ASSERT_TRUE(second);
+ EXPECT_EQ(second->SKind, Scalar::SK_Double);
+ EXPECT_EQ(second->DoubleValue, 1.0);
+ }
+}
+
+TEST(YAMLIO, TestReadWritePolymorphicMap) {
+ std::string intermediate;
+ {
+ auto map = llvm::make_unique<Map>();
+ (*map)["foo"] = llvm::make_unique<Scalar>(false);
+ (*map)["bar"] = llvm::make_unique<Scalar>(2.0);
+ std::unique_ptr<Poly> node = llvm::unique_dyn_cast<Poly>(map);
+
+ llvm::raw_string_ostream ostr(intermediate);
+ Output yout(ostr);
+ yout << node;
+ }
+ {
+ Input yin(intermediate);
+ std::unique_ptr<Poly> node;
+ yin >> node;
+
+ EXPECT_FALSE(yin.error());
+ auto map = llvm::dyn_cast<Map>(node.get());
+ ASSERT_TRUE(map);
+ auto foo = llvm::dyn_cast<Scalar>((*map)["foo"].get());
+ ASSERT_TRUE(foo);
+ EXPECT_EQ(foo->SKind, Scalar::SK_Bool);
+ EXPECT_FALSE(foo->BoolValue);
+ auto bar = llvm::dyn_cast<Scalar>((*map)["bar"].get());
+ ASSERT_TRUE(bar);
+ EXPECT_EQ(bar->SKind, Scalar::SK_Double);
+ EXPECT_EQ(bar->DoubleValue, 2.0);
+ }
+}
OpenPOWER on IntegriCloud