message: Add unit test for ParaView restart mode
diff: #include "mfem.hpp"
  #include "unit_tests.hpp"
  +#include "general/tinyxml2.h"
  #include <stdio.h>
  #ifndef _WIN32
  @@ -235,3 +236,86 @@ TEST_CASE("Save and load from collections", "[DataCollection]")
  }
  }
  +
  +void SaveDataCollection(DataCollection &dc, int cycle, double t)
  +{
  + dc.SetCycle(cycle);
  + dc.SetTime(t);
  + dc.Save();
  +}
  +
  +TEST_CASE("ParaView restart mode", "[ParaView]")
  +{
  + Mesh mesh = Mesh::MakeCartesian2D(2, 3, Element::QUADRILATERAL);
  + H1_FECollection fec(1, mesh.Dimension());
  + FiniteElementSpace fes(&mesh, &fec);
  + GridFunction u(&fes);
  + u = 0.0;
  +
  + // Write initial dataset with three timesteps: 0, 1, 2.
  + {
  + ParaViewDataCollection dc("ParaView", &mesh);
  + dc.RegisterField("u", &u);
  + SaveDataCollection(dc, 0, 0);
  + SaveDataCollection(dc, 1, 1);
  + SaveDataCollection(dc, 2, 2);
  + }
  +
  + // Using restart mode, append to the existing dataset, overwriting timesteps
  + // 1 and 2 with 1 and 1.5.
  + {
  + ParaViewDataCollection dc("ParaView", &mesh);
  + dc.UseRestartMode(true);
  + dc.RegisterField("u", &u);
  + SaveDataCollection(dc, 1, 1.0);
  + SaveDataCollection(dc, 2, 1.5);
  + }
  +
  + // Parse the resulting PVD file, and verify that the structure is correct,
  + // and that it contains three timesteps: 0, 1, and 1.5.
  + using namespace tinyxml2;
  + auto StringCompare = [](const char *s1, const char *s2)
  + {
  + if (s1 == NULL || s2 == NULL) { return false; }
  + return strcmp(s1, s2) == 0;
  + };
  + auto VerifyDataset = [StringCompare](const XMLElement *ds, double t_ref)
  + {
  + REQUIRE(ds);
  + REQUIRE(StringCompare(ds->Name(), "DataSet"));
  + const char *timestep = ds->Attribute("timestep");
  + REQUIRE(timestep);
  + double t = std::stod(timestep);
  + REQUIRE(t == MFEM_Approx(t_ref));
  + };
  +
  + XMLDocument xml;
  + xml.LoadFile("ParaView/ParaView.pvd");
  + REQUIRE(xml.ErrorID() == XML_SUCCESS);
  +
  + const XMLElement *vtkfile = xml.FirstChildElement();
  + REQUIRE(vtkfile);
  + REQUIRE(StringCompare(vtkfile->Name(), "VTKFile"));
  + const XMLElement *collection = vtkfile->FirstChildElement();
  + REQUIRE(collection);
  + REQUIRE(StringCompare(collection->Name(), "Collection"));
  +
  + const XMLElement *dataset = collection->FirstChildElement();
  + VerifyDataset(dataset, 0.0);
  + dataset = dataset->NextSiblingElement();
  + VerifyDataset(dataset, 1.0);
  + dataset = dataset->NextSiblingElement();
  + VerifyDataset(dataset, 1.5);
  + REQUIRE(dataset->NextSiblingElement() == NULL);
  +
  + // Clean up
  + for (int c=0; c<=2; ++c)
  + {
  + std::string prefix = "ParaView/Cycle00000" + std::to_string(c);
  + REQUIRE(remove((prefix + "/data.pvtu").c_str()) == 0);
  + REQUIRE(remove((prefix + "/proc000000.vtu").c_str()) == 0);
  + REQUIRE(rmdir(prefix.c_str()) == 0);
  + }
  + REQUIRE(remove("ParaView/ParaView.pvd") == 0);
  + REQUIRE(rmdir("ParaView") == 0);
  +}
  