SP3_T.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 #include "TestUtil.hpp"
40 #include "SP3Header.hpp"
41 #include "SP3Data.hpp"
42 #include "SP3Stream.hpp"
43 #include <iostream>
44 
45 class SP3_T
46 {
47 public:
48 
49  // test the input and output of SP3 files
50  //
51  // @param ver SP3 version as enumerated in SP3Header::Version
52  // @param inFile unique snippet of the test input file name,
53  // i.e. FFF in ".../test_input_FFF.sp3"
54  //
55  // @return number of failures, i.e., 0=PASS, !0=FAIL
56  //
57  int doReadWriteTests(gnsstk::SP3Header::Version ver, const std::string& inFile)
58  {
59  gnsstk::TestUtil tester( "SP3Data", "Read/Write (" + inFile + ")", __FILE__, __LINE__ );
60 
61  std::string dataFilePath = gnsstk::getPathData();
62  std::string dataFileName = dataFilePath + gnsstk::getFileSep() +
63  "test_input_" + inFile + ".sp3";
64  gnsstk::SP3Stream inStream(dataFileName.c_str(), std::ios::in);
65 
66  tester.assert( inStream.good(), "error creating input stream", __LINE__ );
67 
68  inStream.exceptions(std::ios_base::failbit);
69 
70  // read in the header
71  try
72  {
73  inStream >> inStream.header;
74  tester.assert( true, "header read successfully", __LINE__ );
75  }
76  catch (gnsstk::Exception& e)
77  {
78  std::ostringstream oss;
79  oss << "stream exception reading header: " << e;
80  tester.assert( false, oss.str(), __LINE__ );
81  }
82  catch (...)
83  {
84  tester.assert( false, "unknown exception reading header", __LINE__ );
85  }
86 
87  // read in all records
88  std::vector<gnsstk::SP3Data> data;
89  while (inStream.good() && (EOF != inStream.peek() ) )
90  {
91  gnsstk::SP3Data record;
92  try
93  {
94  inStream >> record;
95  data.push_back(record);
96  }
97  catch (gnsstk::Exception& e)
98  {
99  std::ostringstream oss;
100  oss << "stream exception reading record: " << e;
101  tester.assert( false, oss.str(), __LINE__ );
102  }
103  catch (...)
104  {
105  tester.assert( false, "unknown exception reading record", __LINE__ );
106  }
107  }
108  inStream.close();
109 
110  std::string tempFilePath = gnsstk::getPathTestTemp();
111  std::string tempFileName = tempFilePath + gnsstk::getFileSep() +
112  "test_output_" + inFile + "_tmp.sp3";
113  gnsstk::SP3Stream outStream(tempFileName.c_str(), std::ios::out);
114 
115  tester.assert( outStream.good(), "error creating ouput stream", __LINE__ );
116 
117  outStream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
118 
119  // write out the header
120  outStream.header = inStream.header;
121  try
122  {
123  outStream << outStream.header;
124  tester.assert( true, "header written successfully", __LINE__ );
125  }
126  catch (gnsstk::Exception& e)
127  {
128  std::ostringstream oss;
129  oss << "stream exception writing header: " << e;
130  tester.assert( false, oss.str(), __LINE__ );
131  }
132  catch (...)
133  {
134  tester.assert( false, "unknown exception writing header", __LINE__ );
135  }
136 
137  // write all records
138  std::vector<gnsstk::SP3Data>::iterator recordIter = data.begin();
139  for ( ; recordIter != data.end(); ++recordIter)
140  {
141  try
142  {
143  outStream << *recordIter;
144  tester.assert( true, "put record", __LINE__ );
145  }
146  catch (gnsstk::Exception& e)
147  {
148  std::ostringstream oss;
149  oss << "exception writing record: " << e;
150  tester.assert( false, oss.str(), __LINE__ );
151  }
152  catch (...)
153  {
154  tester.assert( false, "unknown exception writing record", __LINE__ );
155  }
156  }
157  outStream.close();
158 
159  // test files for equality
160  int diff = compareFiles(dataFileName, tempFileName);
161  std::ostringstream diffoss;
162  diffoss << "files '" << dataFileName << "' and '" << tempFileName
163  << "' should be equal but differ on"
164  << " line " << (diff >> 8)
165  << " column " << ((diff & 0xFF) + 1);
166  tester.assert( (0 == diff), diffoss.str(), __LINE__ );
167 
168  return tester.countFails();
169  }
170 
171  // compare two SP3 files byte by byte allowing for differing trailing
172  // whitespace and differing fixed point notation ( 0.01 vs .01 ).
173  // An exception is thrown if the reference file contains a line
174  // of invalid length (>80 bytes).
175  //
176  // @param refFile "truth" file
177  // @param checkFile file to compare to "truth" file
178  //
179  // @return 0 if equal, otherwise return the location in refFile where
180  // it first differs from checkFile. The location is stored as an
181  // integer equal to (line number << 8) + column, where 0 <= column < 256.
182  // In other words the least significant byte of the return value contains
183  // a column number, and the remaining bytes contain a line number.
184  //
185  int compareFiles( const std::string& refFile,
186  const std::string& checkFile )
187  {
188  std::ifstream refStream;
189  std::ifstream checkStream;
190  std::string refLine;
191  std::string checkLine;
192  int lineNumber = 0;
193 
194  refStream.open( refFile.c_str() );
195  checkStream.open( checkFile.c_str() );
196 
197  // Compare each line until you reach the end of Ref
198  while ( !refStream.eof() )
199  {
200  ++lineNumber;
201 
202  // If we reach the end of Check, but there is
203  // more left in Ref, then they are not equal
204  if ( checkStream.eof() )
205  {
206  return (lineNumber << 8);
207  }
208 
209  // get the next line and compare
210  getline( refStream, refLine );
211  getline( checkStream, checkLine );
212 
213  // ignore trailing spaces
214  std::size_t idx = refLine.find_last_not_of(" \t\r\n\f\v");
215  if (idx != std::string::npos)
216  refLine.erase(idx+1);
217  else
218  refLine.clear(); // all whitespace
219  idx = checkLine.find_last_not_of(" \t\r\n\f\v");
220  if (idx != std::string::npos)
221  checkLine.erase(idx+1);
222  else
223  checkLine.clear(); // all whitespace
224 
225  // check remaining line length
226  if (refLine.size() != checkLine.size())
227  {
228  return (lineNumber << 8);
229  }
230 
231  // compare character by character
232  int lastPos = refLine.size() - 1;
233  if (lastPos > 80)
234  {
235  std::ostringstream oss;
236  oss << "Line " << lineNumber << " in the reference file exceeeds "
237  << "the maximum valid SP3 line length (80)";
238  gnsstk::Exception exc(oss.str());
239  GNSSTK_THROW(exc);
240  }
241  for (int pos = 0; pos <= lastPos; ++pos)
242  {
243  if (refLine[pos] != checkLine[pos])
244  {
245  if (pos >= lastPos - 1)
246  {
247  return (lineNumber << 8) + pos;
248  }
249 
250  // determine if the difference is due to fixed-point format
251  switch (refLine[pos])
252  {
253  case ' ': // -.3 vs -0.3 OR .3 vs 0.3
254  if (('-' == refLine[pos + 1]) && ('.' == refLine[pos + 2]))
255  {
256  if (('-' == checkLine[pos]) && ('0' == checkLine[pos + 1]))
257  {
258  ++pos; // advance to the decimal
259  continue; // OK
260  }
261  }
262  else if ('.' == refLine[pos + 1])
263  {
264  if ('0' == checkLine[pos])
265  {
266  continue; // OK
267  }
268  }
269  break;
270 
271  case '-': // -0.3 vs -.3
272  if ((' ' == checkLine[pos]) && ('0' == refLine[pos + 1]) && ('.' == refLine[pos + 2]))
273  {
274  continue; // OK
275  }
276  break;
277 
278  case '0': // 0.3 vs .3
279  if ((' ' == checkLine[pos]) && ('.' == refLine[pos + 1]))
280  {
281  continue; // OK
282  }
283  break;
284 
285  } // switch()
286 
287  return (lineNumber << 8) + pos;
288  }
289  }
290  }
291 
292  // If we reach the end of Ref, but there is
293  // more left in Check, then they are not equal
294  return ( checkStream.eof() ? 0 : (lineNumber << 8) );
295  }
296 
297 }; // class SP3_T
298 
299 
300 int main() //Main function to initialize and run all tests above
301 {
302  int errorTotal = 0;
303 
304  SP3_T testClass; // test data is loaded here
305 
306  try
307  {
308  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3a, "SP3a");
309  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3a, "SP3ae");
310  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3b, "SP3b");
311  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c");
312  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3d, "SP3d");
313 
314  // The SP3c_mgex# series tries do approximate a set of "unit" tests using
315  // mocked SP3c files. Multiple satellite systems, unusual time systems,
316  // unusual reference frames, etc, are all fair game. SP3c file comments
317  // describe the types SP3 features that it intends to exercise.
318  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex1");
319  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex2");
320  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex3");
321  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex4");
322  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex5");
323  errorTotal += testClass.doReadWriteTests(gnsstk::SP3Header::SP3c, "SP3c_mgex6");
324  }
325  catch (gnsstk::Exception& e)
326  {
327  ++errorTotal;
328  std::cerr << "unexpected exception executing tests: " << e;
329  }
330  catch (std::exception& e)
331  {
332  ++errorTotal;
333  std::cerr << "unexpected exception executing tests: " << e.what();
334  }
335  catch (...)
336  {
337  ++errorTotal;
338  std::cerr << "unexpected exception executing tests";
339  }
340  return( errorTotal );
341 }
SP3Header.hpp
gnsstk::TestUtil::countFails
int countFails(void)
Definition: TestUtil.hpp:771
gnsstk::TestUtil::assert
void assert(bool testExpression, const std::string &testMsg, const int lineNumber)
Definition: TestUtil.hpp:607
main
int main()
Definition: SP3_T.cpp:300
SP3Data.hpp
gnsstk::SP3Header::SP3d
@ SP3d
SP3 version d (Expanded Satellites and Comments)
Definition: SP3Header.hpp:80
dataFilePath
string dataFilePath
Definition: Rinex3Obs_FromScratch_T.cpp:51
gnsstk::SP3Stream::header
SP3Header header
SP3Header for this file.
Definition: SP3Stream.hpp:88
gnsstk::Exception::what
std::string what() const
Dump to a string.
Definition: Exception.cpp:193
SP3_T::compareFiles
int compareFiles(const std::string &refFile, const std::string &checkFile)
Definition: SP3_T.cpp:185
SP3_T::doReadWriteTests
int doReadWriteTests(gnsstk::SP3Header::Version ver, const std::string &inFile)
Definition: SP3_T.cpp:57
gnsstk::Exception
Definition: Exception.hpp:151
TestUtil.hpp
gnsstk::SP3Header::SP3b
@ SP3b
SP3 version b (very similar to SP3a)
Definition: SP3Header.hpp:78
gnsstk::SP3Stream
Definition: SP3Stream.hpp:61
gnsstk::SP3Stream::close
virtual void close(void)
Definition: SP3Stream.cpp:74
example4.pos
pos
Definition: example4.py:125
example3.data
data
Definition: example3.py:22
gnsstk::SP3Header::SP3a
@ SP3a
SP3 version a.
Definition: SP3Header.hpp:77
SP3Stream.hpp
gnsstk::SP3Header::Version
Version
Definition: SP3Header.hpp:74
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
gnsstk::SP3Data
Definition: SP3Data.hpp:96
gnsstk::TestUtil
Definition: TestUtil.hpp:265
gnsstk::SP3Header::SP3c
@ SP3c
SP3 version c (contains a/b as a subset)
Definition: SP3Header.hpp:79
tempFilePath
string tempFilePath
Definition: Rinex3Obs_FromScratch_T.cpp:50
SP3_T
Definition: SP3_T.cpp:45


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:41