1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestUnicodeStringArrayAPI.cxx
5 
6 -------------------------------------------------------------------------
7   Copyright 2008 Sandia Corporation.
8   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9   the U.S. Government retains certain rights in this software.
10 -------------------------------------------------------------------------
11 
12   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
13   All rights reserved.
14   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
15 
16      This software is distributed WITHOUT ANY WARRANTY; without even
17      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
18      PURPOSE.  See the above copyright notice for more information.
19 
20 =========================================================================*/
21 
22 #include <vtkSmartPointer.h>
23 #include <vtkUnicodeStringArray.h>
24 #include <vtkIdList.h>
25 #include <vtkDoubleArray.h>
26 #include <vtkVariant.h>
27 #include <vtkTestErrorObserver.h>
28 
29 #include <iterator>
30 #include <iostream>
31 #include <sstream>
32 #include <stdexcept>
33 
34 static int TestErrorsAndWarnings();
35 
36 #define test_expression(expression) \
37 { \
38   if(!(expression)) \
39   { \
40     std::ostringstream buffer; \
41     buffer << "Expression failed at line " << __LINE__ << ": " << #expression; \
42     throw std::runtime_error(buffer.str()); \
43   } \
44 }
45 
46 // Sample strings - nothing risque, I hope ...
47 static const vtkUnicodeString sample_utf8_ascii = vtkUnicodeString::from_utf8("abcde123");
48 static const vtkUnicodeString sample_utf8_greek = vtkUnicodeString::from_utf8("\xce\xb1\xce\xb2\xce\xb3"); // Greek lower-case alpha, beta, gamma.
49 static const vtkUnicodeString sample_utf8_thai = vtkUnicodeString::from_utf8("\xe0\xb8\x81\xe0\xb8\x82\xe0\xb8\x83"); // Thai ko kai, kho khai, kho khuat.
50 static const vtkUnicodeString sample_utf8_linear_b = vtkUnicodeString::from_utf8("\xf0\x90\x80\x80\xf0\x90\x80\x81\xf0\x90\x80\x82\xf0\x90\x80\x83\xf0\x90\x80\x84"); // Linear-B syllables a, e, i, o, u.
51 static const vtkUnicodeString sample_utf8_mixed = vtkUnicodeString::from_utf8("a\xce\xb1\xe0\xb8\x81\xf0\x90\x80\x80"); // a, alpha, ko kai, syllable-a.
52 
TestUnicodeStringArrayAPI(int,char * [])53 int TestUnicodeStringArrayAPI(int, char*[])
54 {
55   try
56   {
57     vtkSmartPointer<vtkUnicodeStringArray> array =
58       vtkSmartPointer<vtkUnicodeStringArray>::New();
59     array->ClearLookup(); // noop
60     test_expression(array->GetNumberOfTuples() == 0);
61     test_expression(array->GetDataType() == VTK_UNICODE_STRING);
62     test_expression(array->GetDataTypeSize() == 0);
63     test_expression(array->GetElementComponentSize() == 4);
64     test_expression(array->IsNumeric() == 0);
65 
66     array->InsertNextValue(sample_utf8_ascii);
67     test_expression(array->GetNumberOfTuples() == 1);
68     test_expression((array->GetValue(0)) == sample_utf8_ascii);
69     test_expression((array->GetVariantValue(0)) == sample_utf8_ascii);
70 
71     array->InsertNextValue(vtkUnicodeString::from_utf8("foo"));
72     test_expression(array->GetNumberOfTuples() == 2);
73     test_expression(array->LookupValue(vtkUnicodeString::from_utf8("foo")) == 1);
74     test_expression(array->LookupValue(vtkUnicodeString::from_utf8("bar")) == -1);
75 
76     vtkSmartPointer<vtkUnicodeStringArray> array2 =
77       vtkSmartPointer<vtkUnicodeStringArray>::New();
78     array2->SetNumberOfTuples(3);
79     array2->SetValue(2, sample_utf8_thai);
80     array2->SetValue(1, sample_utf8_greek);
81     array2->SetValue(0, sample_utf8_linear_b);
82     test_expression(array2->GetNumberOfTuples() == 3);
83 
84     array2->InsertNextUTF8Value("bar");
85     test_expression(array2->GetNumberOfTuples() == 4);
86 
87     array2->InsertValue(100, sample_utf8_ascii);
88     test_expression(array2->GetNumberOfTuples() == 101);
89 
90     array2->SetVariantValue(100, "foo");
91     test_expression(array2->GetValue(100) == vtkUnicodeString::from_utf8("foo"));
92 
93     array2->SetUTF8Value(100, "barfoo");
94     test_expression(strcmp(array2->GetUTF8Value(100), "barfoo") == 0);
95 
96     array2->Initialize();
97     test_expression(array2->GetNumberOfTuples() ==  0);
98 
99     vtkSmartPointer<vtkUnicodeStringArray> array3 =
100       vtkSmartPointer<vtkUnicodeStringArray>::New();
101     void * ptr1 = array3->GetVoidPointer(0);
102     test_expression(ptr1 == nullptr);
103 
104     array3->InsertTuple(0, 1, array);
105     test_expression(array3->GetValue(0) == array->GetValue(1));
106 
107     array3->InsertTuple(100, 1, array);
108     test_expression(array3->GetValue(100) == array->GetValue(1));
109 
110     array3->InsertNextTuple(1, array);
111     test_expression(array3->GetValue(101) == array->GetValue(1));
112 
113     array3->SetTuple(0, 0, array);
114     test_expression(array3->GetValue(0) == array->GetValue(0));
115 
116     vtkSmartPointer<vtkIdList> toIds =
117       vtkSmartPointer<vtkIdList>::New();
118     vtkSmartPointer<vtkIdList> fromIds =
119       vtkSmartPointer<vtkIdList>::New();
120     fromIds->InsertId(0, 1);
121     fromIds->InsertId(1, 0);
122     toIds->InsertId(0, array3->GetNumberOfTuples() + 1);
123     toIds->InsertId(1, 1);
124 
125     array3->InsertTuples(toIds, fromIds, array);
126     test_expression(array3->GetValue(array3->GetNumberOfTuples() - 1) == array->GetValue(1));
127     test_expression(array3->GetValue(1) == array->GetValue(0));
128 
129     array3->InsertNextValue(vtkUnicodeString::from_utf8("foobar"));
130     array3->InsertNextValue(vtkUnicodeString::from_utf8("foobar"));
131     array3->InsertNextValue(vtkUnicodeString::from_utf8("foobar"));
132     vtkSmartPointer<vtkIdList> lookupIds =
133       vtkSmartPointer<vtkIdList>::New();
134     array3->LookupValue(vtkUnicodeString::from_utf8("foobar"), lookupIds);
135     test_expression(lookupIds->GetNumberOfIds() == 3);
136 
137     array3->DeepCopy(nullptr); // noop
138     array3->DeepCopy(array3); // noop
139     array3->DeepCopy(array);
140     test_expression(array3->GetActualMemorySize() == array->GetActualMemorySize());
141 
142     vtkSmartPointer<vtkUnicodeStringArray> array4 =
143       vtkSmartPointer<vtkUnicodeStringArray>::New();
144     array4->InsertNextValue(vtkUnicodeString::from_utf8("array4_0"));
145     array4->InsertNextValue(vtkUnicodeString::from_utf8("array4_1"));
146     array4->InsertNextValue(vtkUnicodeString::from_utf8("array4_2"));
147 
148     vtkSmartPointer<vtkUnicodeStringArray> array5 =
149       vtkSmartPointer<vtkUnicodeStringArray>::New();
150     array5->InsertNextValue(vtkUnicodeString::from_utf8("array5_0"));
151     array5->InsertNextValue(vtkUnicodeString::from_utf8("array5_1"));
152     array5->InsertNextValue(vtkUnicodeString::from_utf8("array5_2"));
153     array5->InsertNextValue(vtkUnicodeString::from_utf8("array5_3"));
154 
155     vtkSmartPointer<vtkIdList> interpIds =
156       vtkSmartPointer<vtkIdList>::New();
157 
158     array3->InterpolateTuple(5, interpIds, array4, nullptr); // noop
159 
160     interpIds->InsertId(0, 0);
161     interpIds->InsertId(1, 1);
162     interpIds->InsertId(2, 2);
163     double weights[3];
164     weights[0] = .2;
165     weights[1] = .8;
166     weights[2] = .5;
167     array3->InterpolateTuple(5, interpIds, array4, weights);
168     test_expression(array3->GetValue(5) == array4->GetValue(1));
169 
170     array3->InterpolateTuple(0,
171                              0, array4,
172                              0, array5,
173                              0.1);
174     test_expression(array3->GetValue(0) == array4->GetValue(0));
175 
176     array3->InterpolateTuple(1,
177                              0, array4,
178                              0, array5,
179                              0.6);
180     test_expression(array3->GetValue(1) == array5->GetValue(0));
181 
182     array3->Squeeze();
183     test_expression(array3->GetValue(5) == array4->GetValue(1));
184 
185     array3->Resize(20);
186     test_expression(array3->GetValue(5) == array4->GetValue(1));
187 
188     array3->GetVoidPointer(0);
189 
190     if (TestErrorsAndWarnings() != 0)
191     {
192       return EXIT_FAILURE;
193     }
194     array3->Print(std::cout);
195 
196     return EXIT_SUCCESS;
197   }
198   catch(std::exception& e)
199   {
200     cerr << e.what() << endl;
201     return EXIT_FAILURE;
202   }
203 }
204 
TestErrorsAndWarnings()205 int TestErrorsAndWarnings()
206 {
207   int status = 0;
208   vtkSmartPointer<vtkTest::ErrorObserver>  errorObserver =
209     vtkSmartPointer<vtkTest::ErrorObserver>::New();
210 
211   vtkSmartPointer<vtkUnicodeStringArray> array =
212     vtkSmartPointer<vtkUnicodeStringArray>::New();
213   array->Allocate(100, 0);
214   array->AddObserver(vtkCommand::ErrorEvent, errorObserver);
215   array->AddObserver(vtkCommand::WarningEvent, errorObserver);
216 
217   // ERROR: Not implemented
218   array->SetVoidArray(nullptr, 1, 1);
219   if (errorObserver->GetError())
220   {
221     std::cout << "Caught expected error: "
222               << errorObserver->GetErrorMessage();
223   }
224   else
225   {
226     std::cout << "Failed to catch expected 'Not implemented' error" << std::endl;
227     ++status;
228   }
229   errorObserver->Clear();
230 
231   // ERROR: Not implemented
232   array->NewIterator();
233   if (errorObserver->GetError())
234   {
235     std::cout << "Caught expected error: "
236               << errorObserver->GetErrorMessage();
237   }
238   else
239   {
240     std::cout << "Failed to catch expected 'Not implemented' error" << std::endl;
241     ++status;
242   }
243   errorObserver->Clear();
244 
245   // Warning: Input and output array data types do not match.
246   vtkSmartPointer<vtkDoubleArray> doubleArray =
247     vtkSmartPointer<vtkDoubleArray>::New();
248   array->SetTuple(0, 0, doubleArray);
249   if (errorObserver->GetWarning())
250   {
251     std::cout << "Caught expected warning: "
252               << errorObserver->GetWarningMessage();
253   }
254   else
255   {
256     std::cout << "Failed to catch expected 'Input and output array data types do not match.' warning" << std::endl;
257     ++status;
258   }
259   errorObserver->Clear();
260 
261   // Warning: Input and output array data types do not match.
262   array->InsertTuple(0, 0, doubleArray);
263   if (errorObserver->GetWarning())
264   {
265     std::cout << "Caught expected warning: "
266               << errorObserver->GetWarningMessage();
267   }
268   else
269   {
270     std::cout << "Failed to catch expected 'Input and output array data types do not match.' warning" << std::endl;
271     ++status;
272   }
273   errorObserver->Clear();
274 
275   // Warning: Input and output array data types do not match.
276   array->InsertNextTuple(0, doubleArray);
277   if (errorObserver->GetWarning())
278   {
279     std::cout << "Caught expected warning: "
280               << errorObserver->GetWarningMessage();
281   }
282   else
283   {
284     std::cout << "Failed to catch expected 'Input and output array data types do not match.' warning" << std::endl;
285     ++status;
286   }
287   errorObserver->Clear();
288 
289   // Warning: Input and output array data types do not match.
290   array->DeepCopy(doubleArray);
291   if (errorObserver->GetWarning())
292   {
293     std::cout << "Caught expected warning: "
294               << errorObserver->GetWarningMessage();
295   }
296   else
297   {
298     std::cout << "Failed to catch expected 'Input and output array data types do not match.' warning" << std::endl;
299     ++status;
300   }
301   errorObserver->Clear();
302 
303   // Warning: Input and output array data types do not match.
304   vtkSmartPointer<vtkIdList> id1 =
305     vtkSmartPointer<vtkIdList>::New();
306   array->InsertTuples(id1, id1, doubleArray);
307   if (errorObserver->GetWarning())
308   {
309     std::cout << "Caught expected warning: "
310               << errorObserver->GetWarningMessage();
311   }
312   else
313   {
314     std::cout << "Failed to catch expected 'Input and output array data types do not match.' warning" << std::endl;
315     ++status;
316   }
317   errorObserver->Clear();
318 
319   // Warning: Input and output id array sizes do not match.
320   vtkSmartPointer<vtkIdList> id2 =
321     vtkSmartPointer<vtkIdList>::New();
322   id1->SetNumberOfIds(10);
323   id2->SetNumberOfIds(5);
324   array->InsertTuples(id1, id2, array);
325   if (errorObserver->GetWarning())
326   {
327     std::cout << "Caught expected warning: "
328               << errorObserver->GetWarningMessage();
329   }
330   else
331   {
332     std::cout << "Failed to catch expected 'Input and output id array sizes do not match.' warning" << std::endl;
333     ++status;
334   }
335   errorObserver->Clear();
336 
337   // ERROR: Cannot CopyValue from array of type
338   array->InterpolateTuple(0, id1, doubleArray, nullptr);
339   if (errorObserver->GetError())
340   {
341     std::cout << "Caught expected warning: "
342               << errorObserver->GetErrorMessage();
343   }
344   else
345   {
346     std::cout << "Failed to catch expected 'Cannot CopyValue from array of type' error" << std::endl;
347     ++status;
348   }
349   errorObserver->Clear();
350 
351   // ERROR: All arrays to InterpolateValue() must be of same type.
352   array->InterpolateTuple(0,
353                           0, doubleArray,
354                           2, array,
355                           0.0);
356   if (errorObserver->GetError())
357   {
358     std::cout << "Caught expected warning: "
359               << errorObserver->GetErrorMessage();
360   }
361   else
362   {
363     std::cout << "Failed to catch expected 'All arrays to InterpolateValue() must be of same type.' error" << std::endl;
364     ++status;
365   }
366   errorObserver->Clear();
367 
368   return status;
369 }
370