1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/pxr.h"
25 #include "pxr/base/tf/regTest.h"
26 #include "pxr/base/tf/diagnostic.h"
27 #include "pxr/base/tf/error.h"
28 #include "pxr/base/tf/errorMark.h"
29 
30 #include "pxr/base/arch/functionLite.h"
31 
32 #include <tbb/tbb_thread.h>
33 
34 #define FILENAME   "error.cpp"
35 
36 #include <string>
37 using std::string;
38 PXR_NAMESPACE_USING_DIRECTIVE
39 
40 enum TfTestErrorCodes { SMALL, MEDIUM, LARGE };
41 
TF_REGISTRY_FUNCTION(TfEnum)42 TF_REGISTRY_FUNCTION(TfEnum) {
43     TF_ADD_ENUM_NAME(SMALL);
44     TF_ADD_ENUM_NAME(MEDIUM);
45     TF_ADD_ENUM_NAME(LARGE);
46 }
47 
48 enum UnRegisteredErrorCode { UNREGISTERED };
49 
50 static bool
Test_TfError()51 Test_TfError()
52 {
53 
54     TfErrorMark m;
55     size_t lineNum;
56 
57     m.SetMark();
58     TF_AXIOM(m.IsClean());
59 
60     m.SetMark();
61     TF_ERROR(SMALL, "small error");
62     lineNum = __LINE__ - 1;
63     TF_AXIOM(!m.IsClean());
64 
65     TfErrorMark::Iterator i = m.GetBegin();
66     TF_AXIOM(i == TfDiagnosticMgr::GetInstance().GetErrorBegin());
67     TfError e = *i;
68     TF_AXIOM(e.GetSourceFileName() == __ARCH_FILE__);
69     TF_AXIOM(e.GetSourceLineNumber() == lineNum);
70     TF_AXIOM(e.GetCommentary() == "small error");
71     TF_AXIOM(e.GetErrorCode() == SMALL);
72     TF_AXIOM(e.GetErrorCodeAsString() == "SMALL");
73     TF_AXIOM(e.GetInfo<int>() == NULL);
74     e.AugmentCommentary("augment");
75     TF_AXIOM(e.GetCommentary() == "small error\naugment");
76     i = TfDiagnosticMgr::GetInstance().EraseError(i);
77     TF_AXIOM(i == TfDiagnosticMgr::GetInstance().GetErrorEnd());
78 
79     m.SetMark();
80     TF_ERROR(1, MEDIUM, "medium error");
81     TF_ERROR(2, LARGE, "large error");
82 
83     i = m.GetBegin();
84     TF_AXIOM(i == TfDiagnosticMgr::GetInstance().GetErrorBegin());
85     e = *i;
86     TF_AXIOM(e.GetErrorCode() == MEDIUM);
87     TF_AXIOM(*e.GetInfo<int>() == 1);
88 
89     ++i;
90     TF_AXIOM(i != TfDiagnosticMgr::GetInstance().GetErrorEnd());
91     e = *i;
92     TF_AXIOM(e.GetErrorCode() == LARGE);
93     TF_AXIOM(*e.GetInfo<int>() == 2);
94 
95     m.Clear();
96     TF_AXIOM(m.IsClean());
97 
98     TF_VERIFY(m.IsClean());
99 
100     TF_AXIOM(TF_VERIFY(m.IsClean()));
101 
102     TF_CODING_ERROR("test error");
103 
104     // It should be the case that m is not clean.
105     TF_AXIOM(TF_VERIFY(!m.IsClean()));
106 
107     // It should not be the case that m is clean.
108     TF_AXIOM(!TF_VERIFY(m.IsClean()));
109 
110     TF_AXIOM(!TF_VERIFY(m.IsClean(), "With a %s", "message."));
111 
112     // Should issue a failed expect error.
113     TF_VERIFY(m.IsClean());
114 
115     m.Clear();
116 
117     // Arbitrary info.
118     std::string info("String containing arbitrary information.");
119 
120     // Issue a few different variations of errors.
121     m.SetMark();
122 
123     string errString = "Error!";
124 
125     TF_CODING_ERROR("Coding error");
126     TF_CODING_ERROR("Coding error %d", 1);
127     TF_CODING_ERROR(errString);
128 
129     TF_RUNTIME_ERROR("Runtime error");
130     TF_RUNTIME_ERROR("Runtime error %d", 1);
131     TF_RUNTIME_ERROR(errString);
132 
133     TF_ERROR(SMALL, "const char *");
134     TF_ERROR(SMALL, "const char *, %s", "...");
135     TF_ERROR(SMALL, errString);
136 
137     TF_ERROR(info, MEDIUM, "const char *");
138     TF_ERROR(info, MEDIUM, "const char *, %s", "...");
139     TF_ERROR(info, MEDIUM, errString);
140 
141     TF_AXIOM(!m.IsClean());
142     m.Clear();
143 
144     // Issue a few different warnings.
145     string warningString = "Warning!";
146 
147     TF_WARN("const char *");
148     TF_WARN("const char *, %s", "...");
149     TF_WARN(warningString);
150 
151     TF_WARN(SMALL, "const char *");
152     TF_WARN(SMALL, "const char *, %s", "...");
153     TF_WARN(SMALL, warningString);
154 
155     TF_WARN(info, MEDIUM, "const char *");
156     TF_WARN(info, MEDIUM, "const char *, %s", "...");
157     TF_WARN(info, MEDIUM, warningString);
158 
159     // Issue a few different status messages.
160     string statusString = "Status";
161 
162     TF_STATUS("const char *");
163     TF_STATUS("const char *, %s", "...");
164     TF_STATUS(statusString);
165 
166     TF_STATUS(SMALL, "const char *");
167     TF_STATUS(SMALL, "const char *, %s", "...");
168     TF_STATUS(SMALL, statusString);
169 
170     TF_STATUS(info, MEDIUM, "const char *");
171     TF_STATUS(info, MEDIUM, "const char *, %s", "...");
172     TF_STATUS(info, MEDIUM, statusString);
173 
174     return true;
175 }
176 
177 TF_ADD_REGTEST(TfError);
178 
179 
180 static void
_ThreadTask(TfErrorTransport * transport)181 _ThreadTask(TfErrorTransport *transport)
182 {
183     TfErrorMark m;
184     printf("Thread issuing error\n");
185     TF_RUNTIME_ERROR("Cross-thread transfer test error");
186     TF_AXIOM(!m.IsClean());
187     m.TransportTo(*transport);
188     TF_AXIOM(m.IsClean());
189 }
190 
191 static bool
Test_TfErrorThreadTransport()192 Test_TfErrorThreadTransport()
193 {
194     TfErrorTransport transport;
195     printf("Creating TfErrorMark\n");
196     TfErrorMark m;
197     printf("Launching thread\n");
198     tbb::tbb_thread t([&transport]() { _ThreadTask(&transport); });
199     TF_AXIOM(m.IsClean());
200     t.join();
201     printf("Thread completed, posting error.\n");
202     TF_AXIOM(m.IsClean());
203     transport.Post();
204     TF_AXIOM(!m.IsClean());
205     m.Clear();
206 
207     return true;
208 }
209 
210 TF_ADD_REGTEST(TfErrorThreadTransport);
211