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/Value.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 namespace {
16 
17 using namespace clang;
18 using namespace dataflow;
19 
20 using test::ConstraintContext;
21 using testing::StrEq;
22 
23 TEST(BoolValueDebugStringTest, AtomicBoolean) {
24   // B0
25   ConstraintContext Ctx;
26   auto B = Ctx.atom();
27 
28   auto Expected = R"(B0)";
29   debugString(*B);
30   EXPECT_THAT(debugString(*B), StrEq(Expected));
31 }
32 
33 TEST(BoolValueDebugStringTest, Negation) {
34   // !B0
35   ConstraintContext Ctx;
36   auto B = Ctx.neg(Ctx.atom());
37 
38   auto Expected = R"((not
39     B0))";
40   EXPECT_THAT(debugString(*B), StrEq(Expected));
41 }
42 
43 TEST(BoolValueDebugStringTest, Conjunction) {
44   // B0 ^ B1
45   ConstraintContext Ctx;
46   auto B = Ctx.conj(Ctx.atom(), Ctx.atom());
47 
48   auto Expected = R"((and
49     B0
50     B1))";
51   EXPECT_THAT(debugString(*B), StrEq(Expected));
52 }
53 
54 TEST(BoolValueDebugStringTest, Disjunction) {
55   // B0 v B1
56   ConstraintContext Ctx;
57   auto B = Ctx.disj(Ctx.atom(), Ctx.atom());
58 
59   auto Expected = R"((or
60     B0
61     B1))";
62   EXPECT_THAT(debugString(*B), StrEq(Expected));
63 }
64 
65 TEST(BoolValueDebugStringTest, Implication) {
66   // B0 => B1, implemented as !B0 v B1
67   ConstraintContext Ctx;
68   auto B = Ctx.disj(Ctx.neg(Ctx.atom()), Ctx.atom());
69 
70   auto Expected = R"((or
71     (not
72         B0)
73     B1))";
74   EXPECT_THAT(debugString(*B), StrEq(Expected));
75 }
76 
77 TEST(BoolValueDebugStringTest, Iff) {
78   // B0 <=> B1, implemented as (!B0 v B1) ^ (B0 v !B1)
79   ConstraintContext Ctx;
80   auto B0 = Ctx.atom();
81   auto B1 = Ctx.atom();
82   auto B = Ctx.conj(Ctx.disj(Ctx.neg(B0), B1), Ctx.disj(B0, Ctx.neg(B1)));
83 
84   auto Expected = R"((and
85     (or
86         (not
87             B0)
88         B1)
89     (or
90         B0
91         (not
92             B1))))";
93   EXPECT_THAT(debugString(*B), StrEq(Expected));
94 }
95 
96 TEST(BoolValueDebugStringTest, Xor) {
97   // (B0 ^ !B1) V (!B0 ^ B1)
98   ConstraintContext Ctx;
99   auto B0 = Ctx.atom();
100   auto B1 = Ctx.atom();
101   auto B = Ctx.disj(Ctx.conj(B0, Ctx.neg(B1)), Ctx.conj(Ctx.neg(B0), B1));
102 
103   auto Expected = R"((or
104     (and
105         B0
106         (not
107             B1))
108     (and
109         (not
110             B0)
111         B1)))";
112   EXPECT_THAT(debugString(*B), StrEq(Expected));
113 }
114 
115 TEST(BoolValueDebugStringTest, NestedBoolean) {
116   // B0 ^ (B1 v (B2 ^ (B3 v B4)))
117   ConstraintContext Ctx;
118   auto B = Ctx.conj(
119       Ctx.atom(),
120       Ctx.disj(Ctx.atom(),
121                Ctx.conj(Ctx.atom(), Ctx.disj(Ctx.atom(), Ctx.atom()))));
122 
123   auto Expected = R"((and
124     B0
125     (or
126         B1
127         (and
128             B2
129             (or
130                 B3
131                 B4)))))";
132   EXPECT_THAT(debugString(*B), StrEq(Expected));
133 }
134 
135 TEST(BoolValueDebugStringTest, AtomicBooleanWithName) {
136   // True
137   ConstraintContext Ctx;
138   auto True = cast<AtomicBoolValue>(Ctx.atom());
139   auto B = True;
140 
141   auto Expected = R"(True)";
142   EXPECT_THAT(debugString(*B, {{True, "True"}}), StrEq(Expected));
143 }
144 
145 TEST(BoolValueDebugStringTest, ComplexBooleanWithNames) {
146   // (Cond ^ Then ^ !Else) v (!Cond ^ !Then ^ Else)
147   ConstraintContext Ctx;
148   auto Cond = cast<AtomicBoolValue>(Ctx.atom());
149   auto Then = cast<AtomicBoolValue>(Ctx.atom());
150   auto Else = cast<AtomicBoolValue>(Ctx.atom());
151   auto B = Ctx.disj(Ctx.conj(Cond, Ctx.conj(Then, Ctx.neg(Else))),
152                     Ctx.conj(Ctx.neg(Cond), Ctx.conj(Ctx.neg(Then), Else)));
153 
154   auto Expected = R"((or
155     (and
156         Cond
157         (and
158             Then
159             (not
160                 Else)))
161     (and
162         (not
163             Cond)
164         (and
165             (not
166                 Then)
167             Else))))";
168   EXPECT_THAT(debugString(*B, {{Cond, "Cond"}, {Then, "Then"}, {Else, "Else"}}),
169               StrEq(Expected));
170 }
171 
172 TEST(BoolValueDebugStringTest, ComplexBooleanWithSomeNames) {
173   // (False && B0) v (True v B1)
174   ConstraintContext Ctx;
175   auto True = cast<AtomicBoolValue>(Ctx.atom());
176   auto False = cast<AtomicBoolValue>(Ctx.atom());
177   auto B = Ctx.disj(Ctx.conj(False, Ctx.atom()), Ctx.disj(True, Ctx.atom()));
178 
179   auto Expected = R"((or
180     (and
181         False
182         B0)
183     (or
184         True
185         B1)))";
186   EXPECT_THAT(debugString(*B, {{True, "True"}, {False, "False"}}),
187               StrEq(Expected));
188 }
189 
190 } // namespace
191