// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-FileCopyrightText: Copyright 2008 Sandia Corporation // SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov #include #include #include "vtkTestErrorObserver.h" #include #include #include #include #include #define test_expression(expression) \ do \ { \ if (!(expression)) \ throw std::runtime_error("Expression failed: " #expression); \ } while (false) int TestArrayAPISparse(int vtkNotUsed(argc), char* vtkNotUsed(argv)[]) { try { // Create an 3D array ... vtkSmartPointer> array = vtkSmartPointer>::New(); array->Resize(vtkArrayExtents::Uniform(3, 0)); test_expression(array); // Test to ensure that casting works correctly ... test_expression(vtkTypedArray::SafeDownCast(array)); test_expression(vtkArray::SafeDownCast(array)); test_expression(vtkObject::SafeDownCast(array)); test_expression(!vtkTypedArray::SafeDownCast(array)); // Confirm the initial state of the array ... test_expression(array->GetDimensions() == 3); test_expression(array->GetSize() == 0); test_expression(array->GetNonNullSize() == 0); test_expression(array->GetExtents() == vtkArrayExtents(0, 0, 0)); // Resize the array and verify that everything adds-up ... array->Resize(vtkArrayExtents(1, 2, 3)); array->SetDimensionLabel(0, "I"); test_expression(array->GetDimensions() == 3); test_expression(array->GetSize() == 6); test_expression(array->GetNonNullSize() == 0); test_expression(array->GetExtents() == vtkArrayExtents(1, 2, 3)); test_expression(array->GetDimensionLabel(0) == "I"); // Verify that the array contains all zeros ... { const vtkArrayExtents extents = array->GetExtents(); for (int i = extents[0].GetBegin(); i != extents[0].GetEnd(); ++i) { for (int j = extents[1].GetBegin(); j != extents[1].GetEnd(); ++j) { for (int k = extents[2].GetBegin(); k != extents[2].GetEnd(); ++k) { test_expression(array->GetValue(vtkArrayCoordinates(i, j, k)) == 0); } } } } // Verify that we can write data into the array with AddValue() and read it out again ... { double value = 0; const vtkArrayExtents extents = array->GetExtents(); for (int i = extents[0].GetBegin(); i != extents[0].GetEnd(); ++i) { for (int j = extents[1].GetBegin(); j != extents[1].GetEnd(); ++j) { for (int k = extents[2].GetBegin(); k != extents[2].GetEnd(); ++k) { array->AddValue(vtkArrayCoordinates(i, j, k), value++); } } } } { double value = 0; vtkIdType index = 0; const vtkArrayExtents extents = array->GetExtents(); for (int i = extents[0].GetBegin(); i != extents[0].GetEnd(); ++i) { for (int j = extents[1].GetBegin(); j != extents[1].GetEnd(); ++j) { for (int k = extents[2].GetBegin(); k != extents[2].GetEnd(); ++k) { test_expression(array->GetValue(i, j, k) == value); test_expression(array->GetValue(vtkArrayCoordinates(i, j, k)) == value); test_expression(array->GetValueN(index) == value); vtkArrayCoordinates coordinates; array->GetCoordinatesN(index, coordinates); test_expression(coordinates[0] == i); test_expression(coordinates[1] == j); test_expression(coordinates[2] == k); ++index; ++value; } } } } // Verify the number of non-null values test_expression(array->GetNonNullSize() == 6); // Verify that deep-copy works correctly ... array->SetNullValue(1.0); vtkSmartPointer> deep_copy; deep_copy.TakeReference(vtkSparseArray::SafeDownCast(array->DeepCopy())); test_expression(deep_copy->GetDimensions() == array->GetDimensions()); test_expression(deep_copy->GetSize() == array->GetSize()); test_expression(deep_copy->GetNonNullSize() == array->GetNonNullSize()); test_expression(deep_copy->GetExtents() == array->GetExtents()); test_expression(deep_copy->GetNullValue() == array->GetNullValue()); for (vtkArray::SizeT n = 0; n != deep_copy->GetNonNullSize(); ++n) { test_expression(deep_copy->GetValueN(n) == array->GetValueN(n)); } // Verify that the Clear() method removes all values from the array ... array->Clear(); test_expression(array->GetDimensions() == 3); test_expression(array->GetSize() == 6); test_expression(array->GetNonNullSize() == 0); test_expression(array->GetExtents() == vtkArrayExtents(1, 2, 3)); // Verify that we can write data into the array with SetValue() // and read it out again ... array->Resize(vtkArrayExtents(2, 3, 4)); array->SetValue(0, 1, 2, 1.1); array->SetValue(vtkArrayCoordinates(1, 2, 3), 2.2); array->SetValue(vtkArrayCoordinates(0, 1, 1), 3.3); test_expression(array->GetSize() == 24); test_expression(array->GetNonNullSize() == 3); test_expression(array->GetValue(vtkArrayCoordinates(0, 1, 2)) == 1.1); test_expression(array->GetValue(0, 1, 2) == 1.1); test_expression(array->GetValue(vtkArrayCoordinates(1, 2, 3)) == 2.2); test_expression(array->GetValue(vtkArrayCoordinates(0, 1, 1)) == 3.3); test_expression(!array->IsDense()); test_expression(array->Validate()); // Verify we can set a value by index array->SetValueN(array->GetNonNullSize() - 1, -1.0); test_expression(array->GetValueN(array->GetNonNullSize() - 1) == -1.0); // Verify the SetExtents works array->SetExtents(vtkArrayExtents(2, 3, 4)); test_expression(array->GetExtents() == vtkArrayExtents(2, 3, 4)); // Verify the sort array->Clear(); array->Resize(vtkArrayExtents(5)); array->AddValue(1, 4.0); array->AddValue(2, 3.0); array->AddValue(0, -5.0); array->AddValue(3, 2.0); array->AddValue(4, 1.0); vtkArraySort arraySort; arraySort.SetDimensions(1); arraySort[0] = 0; array->Sort(arraySort); const vtkSparseArray::CoordinateT* coords = array->GetCoordinateStorage(0); for (unsigned int i = 0; i < array->GetNonNullSize() - 1; ++i) { test_expression(coords[i] < coords[i + 1]); } // ------------------------------------------------------------ // Verify Set/Add/GetValue and SetExtentsFromContents for 0, 1, 2 // dimension API's vtkSmartPointer> array1D = vtkSmartPointer>::New(); array1D->Resize(vtkArrayExtents::Uniform(1, 0)); array1D->SetValue(0, 1.0); array1D->AddValue(0, 2.0); test_expression(!array1D->GetValue(1)); test_expression(array1D->GetExtents() == vtkArrayExtents(0)); std::vector::CoordinateT> coords1DU = array1D->GetUniqueCoordinates(0); test_expression(!(coords1DU.size() == array1D->GetNonNullSize())); vtkArrayCoordinates coord1D; coord1D.SetDimensions(1); coord1D[0] = 3; array1D->SetValue(coord1D, 1.0); test_expression(array1D->GetValue(3) == 1.0); array1D->SetValue(coord1D, 1.1); test_expression(array1D->GetValue(3) == 1.1); array1D->SetValue(2, 1.0); array1D->SetValue(2, 2.0); array1D->AddValue(9, 1.0); test_expression(array1D->GetValue(9) == 1.0); test_expression(!array1D->GetValue(5)); double* values = array1D->GetValueStorage(); test_expression(values[0] == 1.0); values[0] = -1.0; test_expression(array1D->GetValue(0) == -1.0); double const* valuesConst = array1D->GetValueStorage(); test_expression(array1D->GetValue(0) == valuesConst[0]); array1D->SetExtentsFromContents(); test_expression(array1D->GetExtents() == vtkArrayExtents(10)); array1D->ReserveStorage(1000); test_expression(array1D->GetNonNullSize() == 1000); vtkSmartPointer> array2D = vtkSmartPointer>::New(); array2D->Resize(vtkArrayExtents::Uniform(2, 0)); array2D->SetValue(0, 0, 2.0); array2D->AddValue(0, 0, 2.0); test_expression(array2D->GetExtents() == vtkArrayExtents(0, 0)); array2D->SetValue(0, 1, 2.0); array2D->SetValue(1, 1, 2.0); array2D->SetValue(1, 1, 3.0); array2D->AddValue(9, 7, 2.0); array2D->AddValue(9, 8, 2.0); test_expression(array2D->GetValue(9, 7) == 2.0); test_expression(array2D->GetValue(9, 8) == 2.0); test_expression(!array2D->GetValue(5, 8)); array2D->SetExtentsFromContents(); test_expression(array2D->GetExtents() == vtkArrayExtents(10, 9)); vtkSmartPointer> array3D = vtkSmartPointer>::New(); array3D->Resize(vtkArrayExtents::Uniform(3, 0)); array3D->SetValue(0, 0, 0, 0.0); array3D->AddValue(0, 0, 0, 3.0); test_expression(array3D->GetExtents() == vtkArrayExtents(0, 0, 0)); array3D->SetValue(9, 7, 7, 3.0); array3D->SetValue(9, 7, 7, 4.0); array3D->SetValue(9, 8, 6, 3.0); array3D->SetValue(9, 8, 7, 3.0); test_expression(array3D->GetValue(9, 7, 7) == 4.0); test_expression(array3D->GetValue(9, 8, 6) == 3.0); test_expression(array3D->GetValue(9, 8, 7) == 3.0); test_expression(!array3D->GetValue(5, 8, 7)); array3D->SetExtentsFromContents(); test_expression(array3D->GetExtents() == vtkArrayExtents(10, 9, 8)); // ------------------------------------------------------------ // Generate some errors and verify error messages where appropriate vtkSmartPointer errorObserver = vtkSmartPointer::New(); array->AddObserver(vtkCommand::ErrorEvent, errorObserver); array1D->AddObserver(vtkCommand::ErrorEvent, errorObserver); array2D->AddObserver(vtkCommand::ErrorEvent, errorObserver); array3D->AddObserver(vtkCommand::ErrorEvent, errorObserver); // Extent array dimension mismatch array1D->SetExtents(vtkArrayExtents(2, 3, 4)); test_expression(errorObserver->GetErrorMessage().find("Extent-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); // Index mismatch errors vtkArrayCoordinates coordND; coordND.SetDimensions(4); array1D->SetValue(coordND, 3.3); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); array1D->AddValue(coordND, 3.3); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); test_expression(!(array->GetValue(coordND) == 3.3)); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); test_expression(!(array1D->GetCoordinateStorage(5))); test_expression( errorObserver->GetErrorMessage().find("Dimension out-of-bounds.") != std::string::npos); errorObserver->Clear(); std::vector::CoordinateT> badcoords = array1D->GetUniqueCoordinates(5); test_expression(badcoords.empty()); test_expression( errorObserver->GetErrorMessage().find("Dimension out-of-bounds.") != std::string::npos); errorObserver->Clear(); double value = 5.5; array->AddValue(0, value); test_expression(!(array->GetValue(0) == 1.1)); test_expression(!(array1D->GetValue(0, 0) == 1.1)); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); array1D->SetValue(0, 0, 1.0); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); test_expression(!(array1D->GetValue(0, 0) == 1.1)); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); array2D->SetValue(0, 0, 0, 2.0); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); test_expression(!(array2D->GetValue(0, 0, 0) == 1.1)); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); array3D->SetValue(0, 3.0); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); test_expression(!(array3D->GetValue(0) == 1.1)); test_expression(errorObserver->GetErrorMessage().find("Index-array dimension mismatch.") != std::string::npos); errorObserver->Clear(); // Verify Sort errors arraySort.SetDimensions(0); array1D->Sort(arraySort); test_expression(errorObserver->GetErrorMessage().find( "Sort must order at least one dimension.") != std::string::npos); errorObserver->Clear(); arraySort.SetDimensions(1); arraySort[0] = 5; array1D->Sort(arraySort); test_expression( errorObserver->GetErrorMessage().find("Sort dimension out-of-bounds.") != std::string::npos); errorObserver->Clear(); // Verify Validate error messages // First, duplicates present array->AddValue(0, 1.1); test_expression(!(array->Validate())); test_expression( errorObserver->GetErrorMessage().find("duplicate coordinates.") != std::string::npos); errorObserver->Clear(); // Second, out-of-bounds present array->AddValue(1000, value); test_expression(!(array->Validate())); test_expression( errorObserver->GetErrorMessage().find("out-of-bound coordinates.") != std::string::npos); errorObserver->Clear(); // Finally, a silent PrintSelf std::ostringstream os; array1D->Print(os); test_expression(os.str().find("NonNullSize:") != std::string::npos); return 0; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return 1; } }