More flexible API for xvg testing
authorTeemu Murtola <teemu.murtola@gmail.com>
Sat, 8 Aug 2015 03:31:33 +0000 (06:31 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Fri, 2 Oct 2015 15:28:43 +0000 (17:28 +0200)
Make checking xvg files with CommandLineTestHelper::setOutputFile()
explicit.  Also unify setOutputFileNoTest() to just have a single
method.  Add a parameter to the method for the caller to provide a
matcher to use for the file contents, and implement three matchers for
exact, xvg, and no matching.

Unify the reference data XML structure for all types of output files,
and make the xslt files aware of this structure.

Rename checkStringBlock() to checkTextBlock() for consistency.

Change-Id: I17d1ca2f5b4f7bad4b41c418c3ecd0d04f962abc

48 files changed:
src/gromacs/analysisdata/tests/refdata/common-referencedata.xsl
src/gromacs/gmxpreprocess/tests/insert-molecules.cpp
src/gromacs/gmxpreprocess/tests/refdata/InsertMoleculesTest_InsertsMoleculesIntoEmptyBox.xml
src/gromacs/gmxpreprocess/tests/refdata/InsertMoleculesTest_InsertsMoleculesIntoEnlargedBox.xml
src/gromacs/gmxpreprocess/tests/refdata/InsertMoleculesTest_InsertsMoleculesIntoExistingConfiguration.xml
src/gromacs/gmxpreprocess/tests/refdata/InsertMoleculesTest_InsertsMoleculesIntoFixedPositions.xml
src/gromacs/gmxpreprocess/tests/solvate.cpp
src/gromacs/selection/tests/refdata/common-referencedata.xsl
src/gromacs/trajectoryanalysis/tests/pairdist.cpp
src/gromacs/trajectoryanalysis/tests/rdf.cpp
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesAllDistances.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesAllDistancesWithCutoff.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesGroupedMaxDistanceWithCutoff.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesGroupedMinDistanceWithCutoff.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesMaxDistance.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesMaxDistanceWithCutoff.xml
src/gromacs/trajectoryanalysis/tests/refdata/PairDistanceModuleTest_ComputesMinDistanceWithCutoff.xml
src/gromacs/trajectoryanalysis/tests/refdata/RdfModuleTest_BasicTest.xml
src/gromacs/trajectoryanalysis/tests/refdata/RdfModuleTest_CalculatesSurf.xml
src/gromacs/trajectoryanalysis/tests/refdata/RdfModuleTest_CalculatesXY.xml
src/gromacs/trajectoryanalysis/tests/refdata/SasaModuleTest_BasicTest.xml
src/gromacs/trajectoryanalysis/tests/refdata/SasaModuleTest_HandlesDynamicCalculationGroup.xml
src/gromacs/trajectoryanalysis/tests/refdata/SasaModuleTest_HandlesDynamicOutputGroup.xml
src/gromacs/trajectoryanalysis/tests/refdata/SasaModuleTest_WritesConnollySurfaceWithSolute.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_BasicTest.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesMaxPDBOutput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesPDBOutputWithNonPDBInput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesPDBOutputWithPDBInput.xml
src/gromacs/trajectoryanalysis/tests/refdata/SelectModuleTest_HandlesSelectedPDBOutput.xml
src/gromacs/trajectoryanalysis/tests/refdata/common-referencedata.xsl
src/gromacs/trajectoryanalysis/tests/refdata/referencedata.xsl
src/gromacs/trajectoryanalysis/tests/sasa.cpp
src/gromacs/trajectoryanalysis/tests/select.cpp
src/gromacs/utility/textreader.cpp
src/gromacs/utility/textreader.h
src/testutils/CMakeLists.txt
src/testutils/cmdlinetest.cpp
src/testutils/cmdlinetest.h
src/testutils/common-referencedata.xsl
src/testutils/refdata.cpp
src/testutils/refdata.h
src/testutils/stringtest.cpp
src/testutils/tests/refdata_tests.cpp
src/testutils/tests/xvgtest_tests.cpp
src/testutils/textblockmatchers.cpp [new file with mode: 0644]
src/testutils/textblockmatchers.h [new file with mode: 0644]
src/testutils/xvgtest.cpp
src/testutils/xvgtest.h

index b6e9bcfdb67f16b17e6b79715d4980024cf82b08..91c7356b87fad8afbb19763aef0d06fc50e461f4 100644 (file)
@@ -68,6 +68,26 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     <xsl:value-of select="."/>
 </xsl:template>
 
+<xsl:template match="OutputFiles">
+    <xsl:if test="*/*">
+        <h2>Output Files</h2>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File">
+    <xsl:if test="*">
+        <h3><xsl:value-of select="@Name"/></h3>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File/String[@Name='Contents']">
+    <pre>
+        <xsl:value-of select="substring(.,2)"/>
+    </pre>
+</xsl:template>
+
 <xsl:template match="InteractiveSession">
     <pre>
         <xsl:for-each select="*">
index 763653bf48a747f89e216b097f510d87bb45226e..0a8cee6a98bbaf5a971a24ceae121c25eb883bc8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/refdata.h"
+#include "testutils/textblockmatchers.h"
 
 namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::ExactTextMatch;
 
 class InsertMoleculesTest : public gmx::test::CommandLineTestBase
 {
     public:
         InsertMoleculesTest()
         {
-            setOutputFile("-o", "out.gro");
+            setOutputFile("-o", "out.gro", ExactTextMatch());
         }
 
         void runTest(const CommandLine &args)
index 34456e4050c61d896ade25cd71354d47de04fca9..922fd729b88125b41ea28797257e7f30643399a3 100644 (file)
@@ -3,7 +3,8 @@
 <ReferenceData>
   <String Name="CommandLine">insert-molecules -box 4 -nmol 5</String>
   <OutputFiles Name="Files">
-    <String Name="-o"><![CDATA[
+    <File Name="-o">
+      <String Name="Contents"><![CDATA[
 test two-residue molecule for insertion
    10
     1X       X1    1   3.071   2.691   0.351
@@ -18,5 +19,6 @@ test two-residue molecule for insertion
    10Y       Y1   10   3.845   1.125   0.921
    4.00000   4.00000   4.00000
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index ee3890841a8c139e9c7482251d7a5ae88317b182..1cd32f61d3dcd9e36795cbd07f5e492d9efca4c0 100644 (file)
@@ -3,7 +3,8 @@
 <ReferenceData>
   <String Name="CommandLine">insert-molecules -box 4 -nmol 2</String>
   <OutputFiles Name="Files">
-    <String Name="-o"><![CDATA[
+    <File Name="-o">
+      <String Name="Contents"><![CDATA[
 Test system for solvate/insert-molecules
    10
     1MeOH   Me1    1   1.970   1.460   1.209
@@ -18,5 +19,6 @@ Test system for solvate/insert-molecules
     4X       X2   10   3.910   3.371   4.028
    4.00000   4.00000   4.00000
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 66153dc9760ce8bc779a9bd1035e1f35cef3816f..185e62a7d3fc3b928612468e062900ccde2279b8 100644 (file)
@@ -3,7 +3,8 @@
 <ReferenceData>
   <String Name="CommandLine">insert-molecules -nmol 1</String>
   <OutputFiles Name="Files">
-    <String Name="-o"><![CDATA[
+    <File Name="-o">
+      <String Name="Contents"><![CDATA[
 Test system for solvate/insert-molecules
     8
     1MeOH   Me1    1   1.970   1.460   1.209
@@ -16,5 +17,6 @@ Test system for solvate/insert-molecules
     4Y       Y1    8   2.335   1.954   0.173
    3.01000   3.01000   3.01000
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index c6d34ac57ef0adf9bb4bf105001909ce7772bd2d..9af0dec512a2f890be7a64e13e724abd60973f6c 100644 (file)
@@ -3,7 +3,8 @@
 <ReferenceData>
   <String Name="CommandLine">insert-molecules -box 4</String>
   <OutputFiles Name="Files">
-    <String Name="-o"><![CDATA[
+    <File Name="-o">
+      <String Name="Contents"><![CDATA[
 test molecule for insertion at origin
     6
     1X       X1    1   0.000   0.000   0.000
@@ -14,5 +15,6 @@ test molecule for insertion at origin
     3X       X2    6   1.893   1.048   1.933
    4.00000   4.00000   4.00000
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 8edf755e621e98dfe7111dd72cd511f638d8c3d9..445e184f75f293e6f5c399bdeb84cdc167112b21 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/testfilemanager.h"
+#include "testutils/textblockmatchers.h"
 
 namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::NoTextMatch;
 
 class SolvateTest : public gmx::test::CommandLineTestBase
 {
     public:
         SolvateTest()
         {
-            setOutputFile("-o", "out.gro");
+            setOutputFile("-o", "out.gro", NoTextMatch());
         }
 
         void runTest(const CommandLine &args)
index b6e9bcfdb67f16b17e6b79715d4980024cf82b08..91c7356b87fad8afbb19763aef0d06fc50e461f4 100644 (file)
@@ -68,6 +68,26 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     <xsl:value-of select="."/>
 </xsl:template>
 
+<xsl:template match="OutputFiles">
+    <xsl:if test="*/*">
+        <h2>Output Files</h2>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File">
+    <xsl:if test="*">
+        <h3><xsl:value-of select="@Name"/></h3>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File/String[@Name='Contents']">
+    <pre>
+        <xsl:value-of select="substring(.,2)"/>
+    </pre>
+</xsl:template>
+
 <xsl:template match="InteractiveSession">
     <pre>
         <xsl:for-each select="*">
index dcbfa20e0070974545e0eed158705a7e3e69224b..75ae35190d018bd2e227c028881840f5af72b1fe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -57,6 +57,7 @@
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/testasserts.h"
+#include "testutils/textblockmatchers.h"
 
 #include "moduletest.h"
 
@@ -64,6 +65,7 @@ namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::NoTextMatch;
 
 /********************************************************************
  * Tests for gmx::analysismodules::PairDistance.
@@ -81,7 +83,7 @@ TEST_F(PairDistanceModuleTest, ComputesAllDistances)
         "-sel", "resindex 3", "-selgrouping", "none"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -94,7 +96,7 @@ TEST_F(PairDistanceModuleTest, ComputesAllDistancesWithCutoff)
         "-cutoff", "1.5"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -107,7 +109,7 @@ TEST_F(PairDistanceModuleTest, ComputesMinDistanceWithCutoff)
         "-cutoff", "1.5"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -120,7 +122,7 @@ TEST_F(PairDistanceModuleTest, ComputesMaxDistance)
         "-type", "max"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -133,7 +135,7 @@ TEST_F(PairDistanceModuleTest, ComputesMaxDistanceWithCutoff)
         "-cutoff", "1.5", "-type", "max"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -146,7 +148,7 @@ TEST_F(PairDistanceModuleTest, ComputesGroupedMinDistanceWithCutoff)
         "-cutoff", "2.5"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -159,7 +161,7 @@ TEST_F(PairDistanceModuleTest, ComputesGroupedMaxDistanceWithCutoff)
         "-cutoff", "3.5", "-type", "max"
     };
     setTopology("simple.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     runTest(CommandLine(cmdline));
 }
 
index db97f2d9294f6ffdf333d14f4aa4f295d1b0a0fa..dae68d2481e32422c6ba3861821bf564ae14188c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -55,6 +55,7 @@
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/testasserts.h"
+#include "testutils/textblockmatchers.h"
 
 #include "moduletest.h"
 
@@ -62,6 +63,7 @@ namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::NoTextMatch;
 
 /********************************************************************
  * Tests for gmx::analysismodules::Rdf.
@@ -80,7 +82,7 @@ TEST_F(RdfModuleTest, BasicTest)
         "-sel", "name OW", "not name OW"
     };
     setTopology("spc216.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     excludeDataset("pairdist");
     runTest(CommandLine(cmdline));
 }
@@ -94,7 +96,7 @@ TEST_F(RdfModuleTest, CalculatesSurf)
         "-sel", "name OW", "not name OW"
     };
     setTopology("spc216.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     excludeDataset("pairdist");
     runTest(CommandLine(cmdline));
 }
@@ -108,7 +110,7 @@ TEST_F(RdfModuleTest, CalculatesXY)
         "-sel", "name OW", "not name OW"
     };
     setTopology("spc216.gro");
-    setOutputFileNoTest("-o", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
     excludeDataset("pairdist");
     // TODO: Consider if it is possible to get a more reproducible result
     // and/or a stricter tolerance (e.g., by checking that the sum of
index 8816f4dafef614f04472d4a685fc92e3faa2ebb0..8501ec8019ee774f871ff9d4fdb3b898b7851992 100644 (file)
@@ -39,4 +39,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 52a9f8878509746cd715f66591e1ee77d628e4db..4f51fffe6771de3c6d8f962e16c672fe49ebd1ee 100644 (file)
@@ -39,4 +39,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index a97626bc925bd5953242de5d7d816b4d1102e7bf..12744e267707994bc68d014eca1fcc4aac48e144 100644 (file)
@@ -30,4 +30,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index f554d8ecfcd5cd1caf150aaf0a2ea8a101269a01..1847a6ca83bdfdb22a3661eeedc1445b061bd0d9 100644 (file)
@@ -30,4 +30,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 0e5510f86ece250ccc3fbd5608d0b71865f8fede..1769bcdeee2aef1c3758f81639fdbc80340b7749 100644 (file)
@@ -15,4 +15,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index fe5f3eeaa0140c2c739f3c0aea01abd77e1f06ce..6be73a9b5a4c5e607a6d2d89513c77a9e93444d5 100644 (file)
@@ -15,4 +15,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 54b4bd6fb088be4ef2296e0129b87f05572e5844..8e82b2fa4e1fc2d996c3b79651a908fa2f1cbacf 100644 (file)
@@ -15,4 +15,7 @@
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 8fff980d76114bf73216d1b24b87817bd7c25995..404dc769df952cbd8047af5e7cb47515e1125ec3 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 1c8be52eaa70f3b7d2ec03e74310194c7ed8fec6..8bd9e7579dc6598b8ac391b9eb36d9d42190e0b3 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index 6fb0ae32418d911476abfa632e87e0b8038b8c35..527c503d6fe36a402af1a4a677727306d859fd4c 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+  </OutputFiles>
 </ReferenceData>
index fd00e6948fd3264aabe2253c292773324834b7c0..316a0a367abb97cd92f5094493b3d536ac0d39a7 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+    <File Name="-or"/>
+    <File Name="-oa"/>
+    <File Name="-tv"/>
+  </OutputFiles>
 </ReferenceData>
index 37fa6a7c8f09199cc000a913121bb08ae1011a17..2f77428b280506bea033f0d7af3dddf50be74620 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+    <File Name="-or"/>
+    <File Name="-oa"/>
+  </OutputFiles>
 </ReferenceData>
index f209a71bd8a7d070c5e5a2f82262d008745dd59d..05187215ba3bd91239b978017f640c342133957f 100644 (file)
       </DataFrame>
     </AnalysisData>
   </OutputData>
+  <OutputFiles Name="Files">
+    <File Name="-o"/>
+    <File Name="-or"/>
+    <File Name="-oa"/>
+  </OutputFiles>
 </ReferenceData>
index 3294dd0626e77cf050ffb68469423eda0d4cbe88..0fe9c5102196d094a3eccf9452040838626ad828 100644 (file)
@@ -16,7 +16,9 @@
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-q"><![CDATA[
+    <File Name="-o"/>
+    <File Name="-q">
+      <String Name="Contents"><![CDATA[
 TITLE     Connolly Dot Surface Generated by gmx sasa
 REMARK    THIS IS A SIMULATION BOX
 CRYST1   59.062   68.451   30.517  90.00  90.00  90.00 P 1           1
@@ -211,5 +213,6 @@ ATOM    187  DOT DOT    11      37.704  24.043 -11.427  1.00  0.00
 TER
 ENDMDL
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index f756d370dcd7c19d55f886941a8ba4dc9fb13b2e..98be7f55304adb14a2c09b3662165eea25fa7187 100644 (file)
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-oi"><![CDATA[
+    <File Name="-oi">
+      <String Name="Contents"><![CDATA[
       0.000    8    1    2    5    6    9   10   13   14    6    1    2    3    7    8    9
       0.000    8    1    3    4    7    8    9   12   13    6    1    2    3    7    8    9
 ]]></String>
-    <String Name="-on"><![CDATA[
+    </File>
+    <File Name="-on">
+      <String Name="Contents"><![CDATA[
 [ y_<_2.5_f0_t0.000 ]
    1    2    5    6    9   10   13   14 
 
 [ y_<_2.5_f1_t0.000 ]
    1    3    4    7    8    9   12   13 
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 0e930e2f22e4f902d4e14a92a199567d007dd54d..e54314c37d23ed6e5d4f36d4ac32d304e95733b5 100644 (file)
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-ofpdb"><![CDATA[
+    <File Name="-ofpdb">
+      <String Name="Contents"><![CDATA[
 TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
@@ -153,5 +154,6 @@ ATOM     15  S2 A RD B   2      40.000  30.000   0.000  0.00  0.00
 TER
 ENDMDL
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 014682743933e43e402aeb42df8a4aa304d5902d..a402ee53d77cd9a3a11d30396bae66be79830499 100644 (file)
@@ -97,7 +97,8 @@
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-ofpdb"><![CDATA[
+    <File Name="-ofpdb">
+      <String Name="Contents"><![CDATA[
 TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
@@ -120,5 +121,6 @@ ATOM     15  S2   RD     1      40.000  30.000   0.000  0.00  0.00
 TER
 ENDMDL
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 90921b3a97f8a817492e5d4cd2a9c1ac8337f768..69cb89741563ca749cf62892c767c2a1d40f34fc 100644 (file)
@@ -97,7 +97,8 @@
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-ofpdb"><![CDATA[
+    <File Name="-ofpdb">
+      <String Name="Contents"><![CDATA[
 TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
@@ -120,5 +121,6 @@ ATOM     15  S2 A RD B   2      40.000  30.000   0.000  0.00  0.00
 TER
 ENDMDL
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index 103ca163b31ce2db04aca283a31ebed49e3fcbf6..29475c56e289267e745deb84b3d9d89db8fff951 100644 (file)
     </AnalysisData>
   </OutputData>
   <OutputFiles Name="Files">
-    <String Name="-ofpdb"><![CDATA[
+    <File Name="-ofpdb">
+      <String Name="Contents"><![CDATA[
 TITLE     frame t= 0.000
 REMARK    THIS IS A SIMULATION BOX
 CRYST1  100.000  100.000  100.000  90.00  90.00  90.00 P 1           1
@@ -152,5 +153,6 @@ ATOM     14  S1 A RD B   2      40.000  20.000   0.000  0.50  0.00
 TER
 ENDMDL
 ]]></String>
+    </File>
   </OutputFiles>
 </ReferenceData>
index b6e9bcfdb67f16b17e6b79715d4980024cf82b08..91c7356b87fad8afbb19763aef0d06fc50e461f4 100644 (file)
@@ -68,6 +68,26 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     <xsl:value-of select="."/>
 </xsl:template>
 
+<xsl:template match="OutputFiles">
+    <xsl:if test="*/*">
+        <h2>Output Files</h2>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File">
+    <xsl:if test="*">
+        <h3><xsl:value-of select="@Name"/></h3>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File/String[@Name='Contents']">
+    <pre>
+        <xsl:value-of select="substring(.,2)"/>
+    </pre>
+</xsl:template>
+
 <xsl:template match="InteractiveSession">
     <pre>
         <xsl:for-each select="*">
index 971d540a3b2cc95f3632ae61b7c0702bff21ec7b..58902364575536a7ae35bfee24b471388f415681 100644 (file)
     <xsl:apply-imports />
 </xsl:template>
 
-<xsl:template match="OutputFiles">
-    <h2>Output Files</h2>
-    <xsl:for-each select="*">
-        <h3><xsl:value-of select="@Name"/></h3>
-        <pre>
-            <xsl:value-of select="."/>
-        </pre>
-    </xsl:for-each>
-</xsl:template>
-
 </xsl:stylesheet>
index ca387efd4ceed24b4febbf5111dccd356f39f152..2ab717e779029ebcf3a4d37d03df0c70516a8de9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -59,6 +59,7 @@
 
 #include "testutils/cmdlinetest.h"
 #include "testutils/testasserts.h"
+#include "testutils/textblockmatchers.h"
 
 #include "moduletest.h"
 
@@ -66,6 +67,8 @@ namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::ExactTextMatch;
+using gmx::test::NoTextMatch;
 
 /********************************************************************
  * Tests for gmx::analysismodules::Sasa.
@@ -83,10 +86,10 @@ TEST_F(SasaModuleTest, BasicTest)
         "-output", "name N CA C O H"
     };
     setTopology("lysozyme.gro");
-    setOutputFileNoTest("-o", "xvg");
-    setOutputFileNoTest("-or", "xvg");
-    setOutputFileNoTest("-oa", "xvg");
-    setOutputFileNoTest("-tv", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
+    setOutputFile("-or", ".xvg", NoTextMatch());
+    setOutputFile("-oa", ".xvg", NoTextMatch());
+    setOutputFile("-tv", ".xvg", NoTextMatch());
     excludeDataset("dgsolv");
     setDatasetTolerance("area", gmx::test::ulpTolerance(8));
     setDatasetTolerance("volume", gmx::test::ulpTolerance(8));
@@ -100,8 +103,8 @@ TEST_F(SasaModuleTest, WritesConnollySurfaceWithSolute)
         "-surface", "atomnr 1"
     };
     setTopology("lysozyme.gro");
-    setOutputFileNoTest("-o", "xvg");
-    setOutputFile("-q", "connolly.pdb");
+    setOutputFile("-o", ".xvg", NoTextMatch());
+    setOutputFile("-q", "connolly.pdb", ExactTextMatch());
     includeDataset("area");
     runTest(CommandLine(cmdline));
 }
@@ -135,9 +138,9 @@ TEST_F(SasaModuleTest, HandlesDynamicOutputGroup)
         "-output", "y > 1.5"
     };
     setTopology("lysozyme.gro");
-    setOutputFileNoTest("-o", "xvg");
-    setOutputFileNoTest("-or", "xvg");
-    setOutputFileNoTest("-oa", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
+    setOutputFile("-or", ".xvg", NoTextMatch());
+    setOutputFile("-oa", ".xvg", NoTextMatch());
     excludeDataset("volume");
     excludeDataset("dgsolv");
     setDatasetTolerance("area", gmx::test::ulpTolerance(8));
@@ -152,9 +155,9 @@ TEST_F(SasaModuleTest, HandlesDynamicCalculationGroup)
         "-output", "y > 1.5 and z > 0"
     };
     setTopology("lysozyme.gro");
-    setOutputFileNoTest("-o", "xvg");
-    setOutputFileNoTest("-or", "xvg");
-    setOutputFileNoTest("-oa", "xvg");
+    setOutputFile("-o", ".xvg", NoTextMatch());
+    setOutputFile("-or", ".xvg", NoTextMatch());
+    setOutputFile("-oa", ".xvg", NoTextMatch());
     excludeDataset("volume");
     excludeDataset("dgsolv");
     setDatasetTolerance("area", gmx::test::ulpTolerance(8));
index 05a24a4707aed057f5583427175a7a749f72b97d..d7d276627f6558715e62fe0ad3da04cf81f6a556 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,6 +54,7 @@
 #include <gtest/gtest.h>
 
 #include "testutils/cmdlinetest.h"
+#include "testutils/textblockmatchers.h"
 
 #include "moduletest.h"
 
@@ -61,6 +62,7 @@ namespace
 {
 
 using gmx::test::CommandLine;
+using gmx::test::ExactTextMatch;
 
 /********************************************************************
  * Tests for gmx::analysismodules::Select.
@@ -78,8 +80,8 @@ TEST_F(SelectModuleTest, BasicTest)
     };
     setTopology("simple.gro");
     setTrajectory("simple.gro");
-    setOutputFile("-oi", "index.dat");
-    setOutputFile("-on", "index.ndx");
+    setOutputFile("-oi", "index.dat", ExactTextMatch());
+    setOutputFile("-on", "index.ndx", ExactTextMatch());
     excludeDataset("cfrac");
     runTest(CommandLine(cmdline));
 }
@@ -93,7 +95,7 @@ TEST_F(SelectModuleTest, HandlesPDBOutputWithNonPDBInput)
     setTopology("simple.gro");
     setTrajectory("simple.gro");
     includeDataset("occupancy");
-    setOutputFile("-ofpdb", "occupancy.pdb");
+    setOutputFile("-ofpdb", "occupancy.pdb", ExactTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -106,7 +108,7 @@ TEST_F(SelectModuleTest, HandlesPDBOutputWithPDBInput)
     setTopology("simple.pdb");
     setTrajectory("simple.gro");
     includeDataset("occupancy");
-    setOutputFile("-ofpdb", "occupancy.pdb");
+    setOutputFile("-ofpdb", "occupancy.pdb", ExactTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -120,7 +122,7 @@ TEST_F(SelectModuleTest, HandlesMaxPDBOutput)
     setTopology("simple.pdb");
     setTrajectory("simple.gro");
     includeDataset("occupancy");
-    setOutputFile("-ofpdb", "occupancy.pdb");
+    setOutputFile("-ofpdb", "occupancy.pdb", ExactTextMatch());
     runTest(CommandLine(cmdline));
 }
 
@@ -134,7 +136,7 @@ TEST_F(SelectModuleTest, HandlesSelectedPDBOutput)
     setTopology("simple.pdb");
     setTrajectory("simple.gro");
     includeDataset("occupancy");
-    setOutputFile("-ofpdb", "occupancy.pdb");
+    setOutputFile("-ofpdb", "occupancy.pdb", ExactTextMatch());
     runTest(CommandLine(cmdline));
 }
 
index 436614964bb9cfea23ed3a83bb5b6e83572dae48..dd727bb93cfd5cd0628a698b23763ed88533399e 100644 (file)
@@ -53,13 +53,8 @@ namespace gmx
 // static
 std::string TextReader::readFileToString(const char *filename)
 {
-    std::string result;
     TextReader  reader(filename);
-    std::string line;
-    while (reader.readLine(&line))
-    {
-        result.append(line);
-    }
+    std::string result(reader.readAll());
     reader.close();
     return result;
 }
@@ -119,6 +114,17 @@ bool TextReader::readLineTrimmed(std::string *line)
     return true;
 }
 
+std::string TextReader::readAll()
+{
+    std::string result;
+    std::string line;
+    while (readLine(&line))
+    {
+        result.append(line);
+    }
+    return result;
+}
+
 void TextReader::close()
 {
     impl_->stream_->close();
index 62607c6499bebb7e11337eaf67d2c6cb6c972ffe..7b3f8e54e278bbcc68d572d85fb0ad5ad49efb0d 100644 (file)
@@ -149,6 +149,14 @@ class TextReader
          */
         bool readLineTrimmed(std::string *line);
 
+        /*! \brief
+         * Reads all remaining lines from the stream as a single string.
+         *
+         * \returns   Full contents of the stream (from the current point to
+         *     the end).
+         */
+        std::string readAll();
+
         /*! \brief
          * Closes the underlying stream.
          */
index f38e9d16503f7f7da6dcc8019b814c2276942e0a..675039cde6df0a188449cbef8a5aa4e34306662b 100644 (file)
@@ -47,6 +47,7 @@ set(TESTUTILS_SOURCES
     testfileredirector.cpp
     testinit.cpp
     testoptions.cpp
+    textblockmatchers.cpp
     xvgtest.cpp)
 
 add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS} ${TESTUTILS_SOURCES})
index 64688b8d862d3d55a48b26d5c41330949538f215..205499b1b65233c1263c5ef389ab8811391a8a11 100644 (file)
@@ -63,7 +63,7 @@
 
 #include "testutils/refdata.h"
 #include "testutils/testfilemanager.h"
-#include "testutils/xvgtest.h"
+#include "testutils/textblockmatchers.h"
 
 namespace gmx
 {
@@ -240,15 +240,20 @@ class CommandLineTestHelper::Impl
     public:
         struct OutputFileInfo
         {
-            OutputFileInfo(const char *option, const std::string &path)
-                : option(option), path(path)
+            OutputFileInfo(const char *option, const std::string &path,
+                           TextBlockMatcherPointer matcher)
+                : option(option), path(path), matcher(move(matcher))
+            {
+            }
+            OutputFileInfo(OutputFileInfo &&other)
+                : option(std::move(other.option)), path(std::move(other.path)),
+                  matcher(std::move(other.matcher))
             {
-                xvg = endsWith(path, ".xvg");
             }
 
-            std::string         option;
-            std::string         path;
-            bool                xvg;
+            std::string              option;
+            std::string              path;
+            TextBlockMatcherPointer  matcher;
         };
 
         typedef std::vector<OutputFileInfo>        OutputFileList;
@@ -324,19 +329,18 @@ void CommandLineTestHelper::setInputFileContents(
 }
 
 void CommandLineTestHelper::setOutputFile(
-        CommandLine *args, const char *option, const char *filename)
+        CommandLine *args, const char *option, const char *filename,
+        const ITextBlockMatcherSettings &matcher)
 {
-    std::string fullFilename = impl_->fileManager_.getTemporaryFilePath(filename);
-    args->addOption(option, fullFilename);
-    impl_->outputFiles_.push_back(Impl::OutputFileInfo(option, fullFilename));
-}
-
-void CommandLineTestHelper::setOutputFileNoTest(
-        CommandLine *args, const char *option, const char *extension)
-{
-    std::string fullFilename = impl_->fileManager_.getTemporaryFilePath(
-                formatString("%d.%s", args->argc(), extension));
+    std::string suffix(filename);
+    if (startsWith(filename, "."))
+    {
+        suffix = formatString("%d.%s", args->argc(), filename);
+    }
+    std::string fullFilename = impl_->fileManager_.getTemporaryFilePath(suffix);
     args->addOption(option, fullFilename);
+    impl_->outputFiles_.push_back(
+            Impl::OutputFileInfo(option, fullFilename, matcher.createMatcher()));
 }
 
 void CommandLineTestHelper::checkOutputFiles(TestReferenceChecker checker) const
@@ -350,18 +354,11 @@ void CommandLineTestHelper::checkOutputFiles(TestReferenceChecker checker) const
              outfile != impl_->outputFiles_.end();
              ++outfile)
         {
-            if (outfile->xvg)
-            {
-                TestReferenceChecker testChecker = checker.checkCompound("File",
-                                                                         outfile->option.c_str());
-                TextInputFile        sis(outfile->path);
-                checkXvgFile(&sis, &testChecker);
-            }
-            else
-            {
-                std::string output = TextReader::readFileToString(outfile->path);
-                outputChecker.checkStringBlock(output, outfile->option.c_str());
-            }
+            TestReferenceChecker fileChecker(
+                    outputChecker.checkCompound("File", outfile->option.c_str()));
+            TextInputFile        stream(outfile->path);
+            outfile->matcher->checkStream(&stream, &fileChecker);
+            stream.close();
         }
     }
 }
@@ -419,15 +416,10 @@ void CommandLineTestBase::setInputFileContents(
 }
 
 void CommandLineTestBase::setOutputFile(
-        const char *option, const char *filename)
-{
-    impl_->helper_.setOutputFile(&impl_->cmdline_, option, filename);
-}
-
-void CommandLineTestBase::setOutputFileNoTest(
-        const char *option, const char *extension)
+        const char *option, const char *filename,
+        const ITextBlockMatcherSettings &matcher)
 {
-    impl_->helper_.setOutputFileNoTest(&impl_->cmdline_, option, extension);
+    impl_->helper_.setOutputFile(&impl_->cmdline_, option, filename, matcher);
 }
 
 CommandLine &CommandLineTestBase::commandLine()
index 6d5fdc2813a1622b828ec8a5b762b114b8e03ad8..d1e18204a3331b0d0f8640024eb2e38ce0731f60 100644 (file)
@@ -61,6 +61,7 @@ class ICommandLineOptionsModule;
 namespace test
 {
 
+class ITextBlockMatcherSettings;
 class TestFileManager;
 class TestReferenceChecker;
 
@@ -187,8 +188,7 @@ class CommandLine
  *
  *   1. Adding input files to a CommandLine instance by generating them from a
  *      string provided in the test (setInputFileContents()).
- *   2. Adding output files to a CommandLine instance (setOutputFile() and
- *      setOutputFileNoTest()).
+ *   2. Adding output files to a CommandLine instance (setOutputFile()).
  *   3. Checking the contents of some of the output files using
  *      TestReferenceData (setOutputFile() and checkOutputFiles()).
  *   4. Static methods for easily executing command-line modules
@@ -276,43 +276,29 @@ class CommandLineTestHelper
          * \param[in,out] args      CommandLine to which to add the option.
          * \param[in]     option    Option to set.
          * \param[in]     filename  Name of the output file.
+         * \param[in]     matcher   Specifies how the contents of the file are
+         *     tested.
          *
-         * This method:
+         * This method does the following:
          *  - Adds \p option to \p args to point a temporary file name
          *    constructed from \p filename.
          *  - Makes checkOutputFiles() to check the contents of the file
-         *    against reference data.
+         *    against reference data, using \p matcher.
          *  - Marks the temporary file for removal at test teardown.
          *
          * \p filename is given to TestTemporaryFileManager to make a unique
-         * filename for the temporary file, but is not otherwise used.
-         *
+         * filename for the temporary file.
+         * If \p filename starts with a dot, a unique number is prefixed (such
+         * that it is possible to create multiple files with the same extension
+         * by just specifying the extension for every call of setOutputFile()).
+         *
+         * If the output file is needed to trigger some computation, or is
+         * unconditionally produced by the code under test, but the contents
+         * are not interesting for the test, use NoTextMatch as the matcher.
          */
         void setOutputFile(CommandLine *args, const char *option,
-                           const char *filename);
-        /*! \brief
-         * Sets an output file parameter.
-         *
-         * \param[in,out] args      CommandLine to which to add the option.
-         * \param[in]     option    Option to set.
-         * \param[in]     extension Extension for the file to create.
-         *
-         * This method:
-         *  - Adds \p option to \p args to point to a temporary file name with
-         *    extension \p extension.
-         *  - Marks the temporary file for removal at test teardown.
-         *
-         * This method provides the mechanism to set output files that are
-         * required to trigger computation of values that are required for
-         * the test.  The contents of the output file are not tested.
-         *
-         * Another use case is to mark files that are unconditionally produced
-         * by the code under test, but do not need to be tested.  This method
-         * makes the test code aware of those files such that it can remove
-         * them at the end of the test.
-         */
-        void setOutputFileNoTest(CommandLine *args, const char *option,
-                                 const char *extension);
+                           const char *filename,
+                           const ITextBlockMatcherSettings &matcher);
 
         /*! \brief
          * Checks output files added with setOutputFile() against reference
@@ -388,13 +374,8 @@ class CommandLineTestBase : public ::testing::Test
          *
          * \see CommandLineTestHelper::setOutputFile()
          */
-        void setOutputFile(const char *option, const char *filename);
-        /*! \brief
-         * Sets an output file parameter.
-         *
-         * \see CommandLineTestHelper::setOutputFileNoTest()
-         */
-        void setOutputFileNoTest(const char *option, const char *extension);
+        void setOutputFile(const char *option, const char *filename,
+                           const ITextBlockMatcherSettings &matcher);
 
         /*! \brief
          * Returns the internal CommandLine object used to construct the
index b6e9bcfdb67f16b17e6b79715d4980024cf82b08..91c7356b87fad8afbb19763aef0d06fc50e461f4 100644 (file)
@@ -68,6 +68,26 @@ and use the copy_xsl.sh script to copy it to relevant locations.
     <xsl:value-of select="."/>
 </xsl:template>
 
+<xsl:template match="OutputFiles">
+    <xsl:if test="*/*">
+        <h2>Output Files</h2>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File">
+    <xsl:if test="*">
+        <h3><xsl:value-of select="@Name"/></h3>
+        <xsl:apply-templates />
+    </xsl:if>
+</xsl:template>
+
+<xsl:template match="OutputFiles/File/String[@Name='Contents']">
+    <pre>
+        <xsl:value-of select="substring(.,2)"/>
+    </pre>
+</xsl:template>
+
 <xsl:template match="InteractiveSession">
     <pre>
         <xsl:for-each select="*">
index 0ba9e343ec79cafa93d2a9f1547e70e275a12802..0f82dffdc574361df85af93592fa931f7f06af26 100644 (file)
@@ -742,8 +742,8 @@ void TestReferenceChecker::checkString(const std::string &value, const char *id)
 }
 
 
-void TestReferenceChecker::checkStringBlock(const std::string &value,
-                                            const char        *id)
+void TestReferenceChecker::checkTextBlock(const std::string &value,
+                                          const char        *id)
 {
     EXPECT_PLAIN(impl_->processItem(Impl::cStringNodeName, id,
                                     ExactStringBlockChecker(value)));
index 0c4d7ca3a0d89cd89628ac79cde1cfb7a66140ba..a571d7a8e1405b8373ef668ea18d24d4a70d87b8 100644 (file)
@@ -306,7 +306,7 @@ class TestReferenceChecker
          * formatted output, and attempts to make the output XML such that it
          * is easier to edit by hand to set the desired output formatting.
          */
-        void checkStringBlock(const std::string &value, const char *id);
+        void checkTextBlock(const std::string &value, const char *id);
         //! Check a single integer value.
         void checkInteger(int value, const char *id);
         //! Check a single int64 value.
index 2ff4a776a20e4b7e27460f2caea7ac3475e2cc0f..4f6daa4b61ab3a2f7e9e0bc333df06b9f3b9e014 100644 (file)
@@ -104,7 +104,7 @@ void StringTestBase::checkText(TestReferenceChecker *checker,
     }
     else
     {
-        checker->checkStringBlock(text, id);
+        checker->checkTextBlock(text, id);
     }
 }
 
index d7f0853e8f455842f88486458b3eb06d0946186e..1331d9eda6e1828f8860a8aef5085ec6f1a907ca 100644 (file)
@@ -138,15 +138,15 @@ TEST(ReferenceDataTest, HandlesStringBlockData)
     {
         TestReferenceData    data(gmx::test::erefdataUpdateAll);
         TestReferenceChecker checker(data.rootChecker());
-        checker.checkStringBlock("Line1\nLine2\n", "block");
+        checker.checkTextBlock("Line1\nLine2\n", "block");
         checker.checkString("Test", "string");
     }
     {
         TestReferenceData    data(gmx::test::erefdataCompare);
         TestReferenceChecker checker(data.rootChecker());
-        checker.checkStringBlock("Line1\nLine2\n", "block");
+        checker.checkTextBlock("Line1\nLine2\n", "block");
         checker.checkString("Line1\nLine2\n", "block");
-        checker.checkStringBlock("Test", "string");
+        checker.checkTextBlock("Test", "string");
     }
 }
 
@@ -270,13 +270,13 @@ TEST(ReferenceDataTest, HandlesSpecialCharactersInStrings)
         TestReferenceChecker checker(data.rootChecker());
         checker.checkString("\"<'>\n \r &\\/;", "string");
         // \r is not handled correctly
-        checker.checkStringBlock("\"<'>\n ]]> &\\/;", "stringblock");
+        checker.checkTextBlock("\"<'>\n ]]> &\\/;", "stringblock");
     }
     {
         TestReferenceData    data(gmx::test::erefdataCompare);
         TestReferenceChecker checker(data.rootChecker());
         checker.checkString("\"<'>\n \r &\\/;", "string");
-        checker.checkStringBlock("\"<'>\n ]]> &\\/;", "stringblock");
+        checker.checkTextBlock("\"<'>\n ]]> &\\/;", "stringblock");
     }
 }
 
@@ -316,16 +316,16 @@ TEST(ReferenceDataTest, HandlesMultipleChecksAgainstSameData)
         TestReferenceChecker checker(data.rootChecker());
         checker.checkString("Test", "string");
         EXPECT_NONFATAL_FAILURE(checker.checkString("Test2", "string"), "");
-        checker.checkStringBlock("TestString", "stringblock");
-        EXPECT_NONFATAL_FAILURE(checker.checkStringBlock("TestString2", "stringblock"), "");
+        checker.checkTextBlock("TestString", "stringblock");
+        EXPECT_NONFATAL_FAILURE(checker.checkTextBlock("TestString2", "stringblock"), "");
     }
     {
         TestReferenceData    data(gmx::test::erefdataCompare);
         TestReferenceChecker checker(data.rootChecker());
         checker.checkString("Test", "string");
         EXPECT_NONFATAL_FAILURE(checker.checkString("Test2", "string"), "");
-        checker.checkStringBlock("TestString", "stringblock");
-        EXPECT_NONFATAL_FAILURE(checker.checkStringBlock("TestString2", "stringblock"), "");
+        checker.checkTextBlock("TestString", "stringblock");
+        EXPECT_NONFATAL_FAILURE(checker.checkTextBlock("TestString2", "stringblock"), "");
     }
 }
 
index 61629ba769f3d14b8794c2578405ec3ce2f29228..5621821b129458020fb8f405f5a766c342aa6d3e 100644 (file)
 
 namespace
 {
+
+using gmx::test::checkXvgFile;
+using gmx::test::XvgMatchSettings;
+
 //! Input testing data - an inline xvg file.
 const char * const input[] = {
     "0     2905.86    -410.199",
@@ -74,7 +78,7 @@ TEST(XvgTests, CreateFile)
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         // Convert char array to a stream and add it to the checker
         gmx::StringInputStream          sis(input);
-        gmx::test::checkXvgFile(&sis, &checker);
+        checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
     {
         // Now read it back
@@ -82,7 +86,7 @@ TEST(XvgTests, CreateFile)
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         // Convert char array to a stream and add it to the checker
         gmx::StringInputStream          sis(input);
-        gmx::test::checkXvgFile(&sis, &checker);
+        checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
 }
 
@@ -94,7 +98,7 @@ TEST(XvgTests, CheckMissing)
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         // Convert char array to a stream and add it to the checker
         gmx::StringInputStream          sis(input);
-        gmx::test::checkXvgFile(&sis, &checker);
+        checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
     {
         const char * const              input[] = {
@@ -106,7 +110,7 @@ TEST(XvgTests, CheckMissing)
         gmx::test::TestReferenceData    data(gmx::test::erefdataCompare);
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         gmx::StringInputStream          sis(input);
-        EXPECT_NONFATAL_FAILURE(gmx::test::checkXvgFile(&sis, &checker), "absent");
+        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "absent");
     }
 }
 
@@ -118,7 +122,7 @@ TEST(XvgTests, CheckExtra)
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         // Convert char array to a stream and add it to the checker
         gmx::StringInputStream          sis(input);
-        gmx::test::checkXvgFile(&sis, &checker);
+        checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
     {
         const char * const              input[] = {
@@ -134,7 +138,7 @@ TEST(XvgTests, CheckExtra)
         gmx::test::TestReferenceData    data(gmx::test::erefdataCompare);
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         gmx::StringInputStream          sis(input);
-        EXPECT_NONFATAL_FAILURE(gmx::test::checkXvgFile(&sis, &checker), "Row6");
+        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "Row6");
     }
 }
 
@@ -146,7 +150,7 @@ TEST(XvgTests, ReadIncorrect)
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         // Convert char array to a stream and add it to the checker
         gmx::StringInputStream          sis(input);
-        gmx::test::checkXvgFile(&sis, &checker);
+        checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
     {
         const char * const              input[] = {
@@ -161,7 +165,7 @@ TEST(XvgTests, ReadIncorrect)
         gmx::test::TestReferenceData    data(gmx::test::erefdataCompare);
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         gmx::StringInputStream          sis(input);
-        EXPECT_NONFATAL_FAILURE(gmx::test::checkXvgFile(&sis, &checker), "-411");
+        EXPECT_NONFATAL_FAILURE(checkXvgFile(&sis, &checker, XvgMatchSettings()), "-411");
     }
 }
 
diff --git a/src/testutils/textblockmatchers.cpp b/src/testutils/textblockmatchers.cpp
new file mode 100644 (file)
index 0000000..78a9cf8
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes from textblockmatchers.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "textblockmatchers.h"
+
+#include "gromacs/utility/textreader.h"
+
+#include "testutils/refdata.h"
+
+namespace gmx
+{
+namespace test
+{
+
+namespace
+{
+
+class ExactTextMatcher : public ITextBlockMatcher
+{
+    public:
+        virtual void checkStream(TextInputStream      *stream,
+                                 TestReferenceChecker *checker)
+        {
+            TextReader reader(stream);
+            checker->checkTextBlock(reader.readAll(), "Contents");
+        }
+};
+
+class NoTextMatcher : public ITextBlockMatcher
+{
+    public:
+        virtual void checkStream(TextInputStream      * /*stream*/,
+                                 TestReferenceChecker * /*checker*/)
+        {
+        }
+};
+
+}       // namespace
+
+ITextBlockMatcher::~ITextBlockMatcher()
+{
+}
+
+ITextBlockMatcherSettings::~ITextBlockMatcherSettings()
+{
+}
+
+TextBlockMatcherPointer ExactTextMatch::createMatcher() const
+{
+    return TextBlockMatcherPointer(new ExactTextMatcher());
+}
+
+TextBlockMatcherPointer NoTextMatch::createMatcher() const
+{
+    return TextBlockMatcherPointer(new NoTextMatcher());
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/testutils/textblockmatchers.h b/src/testutils/textblockmatchers.h
new file mode 100644 (file)
index 0000000..e111b1d
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares utility classes for testing multi-line strings against reference data.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_TEXTBLOCKMATCHERS_H
+#define GMX_TESTUTILS_TEXTBLOCKMATCHERS_H
+
+#include <memory>
+#include <string>
+
+namespace gmx
+{
+
+class TextInputStream;
+
+namespace test
+{
+
+class TestReferenceChecker;
+
+/*! \libinternal \brief
+ * Represents a text matcher, matching text stream contents against reference
+ * data.
+ *
+ * Typical pattern of declaring such matchers is to
+ *  - Create a factory that implements ITextBlockMatcherSettings,
+ *  - Make that factory provide any necessary parameters that the matcher needs,
+ *    using a "named parameter" idiom (see XvgMatch for an example), and
+ *  - Make the factory create and return an instance of an internal
+ *    implementation class that implements ITextBlockMatcher and provides
+ *    the actual matching logic.
+ *
+ * Any method that then wants to accept a matcher can accept a
+ * ITextBlockMatcherSettings.
+ *
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+class ITextBlockMatcher
+{
+    public:
+        virtual ~ITextBlockMatcher();
+
+        /*! \brief
+         * Matches contents of a stream against reference data.
+         *
+         * \param  stream   Stream to match.
+         * \param  checker  Checker to use for matching.
+         *
+         * The method can change the state of the provided checker (e.g., by
+         * changing the default tolerance).
+         * The caller is responsible of providing a checker where such state
+         * changes do not matter.
+         */
+        virtual void checkStream(TextInputStream      *stream,
+                                 TestReferenceChecker *checker) = 0;
+};
+
+//! Smart pointer for managing a ITextBlockMatcher.
+typedef std::unique_ptr<ITextBlockMatcher> TextBlockMatcherPointer;
+
+/*! \libinternal \brief
+ * Represents a factory for creating a text matcher.
+ *
+ * See derived classes for available matchers.  Each derived class represents
+ * one type of matcher (see ITextBlockMatcher), and provides any methods
+ * necessary to pass parameters to such a matcher.  Methods that accept a
+ * matcher can then take in this interface, and call createMatcher() to use the
+ * matcher that the caller of the method specifies.
+ *
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+class ITextBlockMatcherSettings
+{
+    public:
+        //! Factory method that constructs the matcher after parameters are set.
+        virtual TextBlockMatcherPointer createMatcher() const = 0;
+
+    protected:
+        virtual ~ITextBlockMatcherSettings();
+};
+
+/*! \libinternal \brief
+ * Use an exact text match (the contents should be exactly equal).
+ *
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+class ExactTextMatch : public ITextBlockMatcherSettings
+{
+    public:
+        virtual TextBlockMatcherPointer createMatcher() const;
+};
+
+/*! \libinternal \brief
+ * Do not match the text (the contents are ignored).
+ *
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+class NoTextMatch : public ITextBlockMatcherSettings
+{
+    public:
+        virtual TextBlockMatcherPointer createMatcher() const;
+};
+
+} // namespace test
+} // namespace gmx
+
+#endif
index d13a6f253f6c440f09671dc1c0419908a6b4e5d2..3940b4c2e720885959188a62970593986ef0e2d6 100644 (file)
@@ -37,6 +37,7 @@
  * Implements routine to check the content of xvg files.
  *
  * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_testutils
  */
 #include "gmxpre.h"
 
 #include "testutils/refdata.h"
 #include "testutils/testasserts.h"
+#include "testutils/textblockmatchers.h"
 
 namespace gmx
 {
-
 namespace test
 {
 
-void checkXvgFile(TextInputStream      *input,
-                  TestReferenceChecker *checker)
+namespace
+{
+
+class XvgMatcher : public ITextBlockMatcher
 {
+    public:
+        explicit XvgMatcher(const XvgMatchSettings &settings)
+            : settings_(settings)
+        {
+        }
+
+        virtual void checkStream(TextInputStream      *stream,
+                                 TestReferenceChecker *checker)
+        {
+            checkXvgFile(stream, checker, settings_);
+        }
+
+    private:
+        XvgMatchSettings  settings_;
+};
+
+}       // namespace
+
+void checkXvgFile(TextInputStream        *input,
+                  TestReferenceChecker   *checker,
+                  const XvgMatchSettings &settings)
+{
+    TestReferenceChecker dataChecker(checker->checkCompound("XvgData", "Data"));
+    dataChecker.setDefaultTolerance(settings.tolerance);
+
     std::string line;
     int         nrow = 0;
 
@@ -95,13 +123,17 @@ void checkXvgFile(TextInputStream      *input,
                 row.push_back(dval);
             }
             std::string buf = formatString("Row%d", nrow++);
-            checker->checkSequence(row.begin(), row.end(), buf.c_str());
+            dataChecker.checkSequence(row.begin(), row.end(), buf.c_str());
         }
     }
     std::string buf = formatString("Row%d", nrow++);
-    checker->checkPresent(false, buf.c_str());
+    dataChecker.checkPresent(false, buf.c_str());
 }
 
-} // namespace test
+TextBlockMatcherPointer XvgMatch::createMatcher() const
+{
+    return TextBlockMatcherPointer(new XvgMatcher(settings_));
+}
 
+} // namespace test
 } // namespace gmx
index d41d218965ff28b526e69f8d640d94d18f27f298..6faecb9f19939f2a27c7ac0542be29143eec896f 100644 (file)
@@ -37,6 +37,7 @@
  * Declares function to add the content of an xvg file to a checker.
  *
  * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \inlibraryapi
  * \ingroup module_testutils
  */
@@ -45,6 +46,9 @@
 
 #include <string>
 
+#include "testutils/testasserts.h"
+#include "testutils/textblockmatchers.h"
+
 namespace gmx
 {
 
@@ -55,6 +59,13 @@ namespace test
 
 class TestReferenceChecker;
 
+struct XvgMatchSettings
+{
+    XvgMatchSettings() : tolerance(defaultRealTolerance()) {}
+
+    FloatingPointTolerance  tolerance;
+};
+
 /*! \brief
  * Adds content of xvg file to TestReferenceChecker object.
  *
@@ -66,10 +77,35 @@ class TestReferenceChecker;
  * \param[in] input       Object returning the lines of the file/data
  *                        one by one.
  * \param[in,out] checker The checker object.
+ * \param[in] settings    Settings to use for matching.
+ */
+void checkXvgFile(TextInputStream        *input,
+                  TestReferenceChecker   *checker,
+                  const XvgMatchSettings &settings);
+
+/*! \libinternal \brief
+ * Match the contents as an xvg file.
+ *
+ * \see checkXvgFile()
+ *
+ * \inlibraryapi
+ * \ingroup module_testutils
  */
-void checkXvgFile(TextInputStream      *input,
-                  TestReferenceChecker *checker);
+class XvgMatch : public ITextBlockMatcherSettings
+{
+    public:
+        //! Sets the tolerance for matching data point values.
+        XvgMatch &tolerance(const FloatingPointTolerance &tolerance)
+        {
+            settings_.tolerance = tolerance;
+            return *this;
+        }
+
+        virtual TextBlockMatcherPointer createMatcher() const;
 
+    private:
+        XvgMatchSettings  settings_;
+};
 
 } // namespace test