1 | //===- unittests/Analysis/FlowSensitive/DebugSupportTest.cpp --------------===// |
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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Analysis/FlowSensitive/DebugSupport.h" |
10 | #include "TestingSupport.h" |
11 | #include "clang/Analysis/FlowSensitive/Formula.h" |
12 | #include "llvm/Support/ScopedPrinter.h" |
13 | #include "llvm/Support/raw_ostream.h" |
14 | #include "gmock/gmock.h" |
15 | #include "gtest/gtest.h" |
16 | |
17 | namespace { |
18 | |
19 | using namespace clang; |
20 | using namespace dataflow; |
21 | |
22 | using test::ConstraintContext; |
23 | using testing::StrEq; |
24 | |
25 | TEST(BoolValueDebugStringTest, AtomicBoolean) { |
26 | ConstraintContext Ctx; |
27 | auto B = Ctx.atom(); |
28 | |
29 | auto Expected = "V0" ; |
30 | EXPECT_THAT(llvm::to_string(*B), StrEq(Expected)); |
31 | } |
32 | |
33 | TEST(BoolValueDebugStringTest, Literal) { |
34 | ConstraintContext Ctx; |
35 | EXPECT_EQ("true" , llvm::to_string(*Ctx.literal(true))); |
36 | EXPECT_EQ("false" , llvm::to_string(*Ctx.literal(false))); |
37 | } |
38 | |
39 | TEST(BoolValueDebugStringTest, Negation) { |
40 | ConstraintContext Ctx; |
41 | auto B = Ctx.neg(Operand: Ctx.atom()); |
42 | |
43 | auto Expected = "!V0" ; |
44 | EXPECT_THAT(llvm::to_string(*B), StrEq(Expected)); |
45 | } |
46 | |
47 | TEST(BoolValueDebugStringTest, Conjunction) { |
48 | ConstraintContext Ctx; |
49 | auto *V0 = Ctx.atom(); |
50 | auto *V1 = Ctx.atom(); |
51 | EXPECT_EQ("(V0 & V1)" , llvm::to_string(*Ctx.conj(V0, V1))); |
52 | } |
53 | |
54 | TEST(BoolValueDebugStringTest, Disjunction) { |
55 | ConstraintContext Ctx; |
56 | auto *V0 = Ctx.atom(); |
57 | auto *V1 = Ctx.atom(); |
58 | EXPECT_EQ("(V0 | V1)" , llvm::to_string(*Ctx.disj(V0, V1))); |
59 | } |
60 | |
61 | TEST(BoolValueDebugStringTest, Implication) { |
62 | ConstraintContext Ctx; |
63 | auto *V0 = Ctx.atom(); |
64 | auto *V1 = Ctx.atom(); |
65 | EXPECT_EQ("(V0 => V1)" , llvm::to_string(*Ctx.impl(V0, V1))); |
66 | } |
67 | |
68 | TEST(BoolValueDebugStringTest, Iff) { |
69 | ConstraintContext Ctx; |
70 | auto *V0 = Ctx.atom(); |
71 | auto *V1 = Ctx.atom(); |
72 | EXPECT_EQ("(V0 = V1)" , llvm::to_string(*Ctx.iff(V0, V1))); |
73 | } |
74 | |
75 | TEST(BoolValueDebugStringTest, Xor) { |
76 | ConstraintContext Ctx; |
77 | auto V0 = Ctx.atom(); |
78 | auto V1 = Ctx.atom(); |
79 | auto B = Ctx.disj(LHS: Ctx.conj(LHS: V0, RHS: Ctx.neg(Operand: V1)), RHS: Ctx.conj(LHS: Ctx.neg(Operand: V0), RHS: V1)); |
80 | |
81 | auto Expected = "((V0 & !V1) | (!V0 & V1))" ; |
82 | EXPECT_THAT(llvm::to_string(*B), StrEq(Expected)); |
83 | } |
84 | |
85 | TEST(BoolValueDebugStringTest, NestedBoolean) { |
86 | ConstraintContext Ctx; |
87 | auto V0 = Ctx.atom(); |
88 | auto V1 = Ctx.atom(); |
89 | auto V2 = Ctx.atom(); |
90 | auto V3 = Ctx.atom(); |
91 | auto V4 = Ctx.atom(); |
92 | auto B = Ctx.conj(LHS: V0, RHS: Ctx.disj(LHS: V1, RHS: Ctx.conj(LHS: V2, RHS: Ctx.disj(LHS: V3, RHS: V4)))); |
93 | |
94 | auto Expected = "(V0 & (V1 | (V2 & (V3 | V4))))" ; |
95 | EXPECT_THAT(llvm::to_string(*B), StrEq(Expected)); |
96 | } |
97 | |
98 | TEST(BoolValueDebugStringTest, ComplexBooleanWithSomeNames) { |
99 | ConstraintContext Ctx; |
100 | auto X = Ctx.atom(); |
101 | auto Y = Ctx.atom(); |
102 | Formula::AtomNames Names; |
103 | Names[X->getAtom()] = "X" ; |
104 | Names[Y->getAtom()] = "Y" ; |
105 | auto V2 = Ctx.atom(); |
106 | auto V3 = Ctx.atom(); |
107 | auto B = Ctx.disj(LHS: Ctx.conj(LHS: Y, RHS: V2), RHS: Ctx.disj(LHS: X, RHS: V3)); |
108 | |
109 | auto Expected = R"(((Y & V2) | (X | V3)))" ; |
110 | std::string Actual; |
111 | llvm::raw_string_ostream OS(Actual); |
112 | B->print(OS, &Names); |
113 | EXPECT_THAT(Actual, StrEq(Expected)); |
114 | } |
115 | |
116 | } // namespace |
117 | |