forked from lijiext/lammps
Merge remote-tracking branch 'origin/master' into varargs-log-error-functions
This commit is contained in:
commit
a9ff9312d6
|
@ -26,11 +26,11 @@ __
|
|||
|
||||
## I don't want to read this whole thing I just have a question!
|
||||
|
||||
> **Note:** Please do not file an issue to ask a general question about LAMMPS, its features, how to use specific commands, or how perform simulations or analysis in LAMMPS. Instead post your question to the ['lammps-users' mailing list](https://lammps.sandia.gov/mail.html). You do not need to be subscribed to post to the list (but a mailing list subscription avoids having your post delayed until it is approved by a mailing list moderator). Most posts to the mailing list receive a response within less than 24 hours. Before posting to the mailing list, please read the [mailing list guidelines](https://lammps.sandia.gov/guidelines.html). Following those guidelines will help greatly to get a helpful response. Always mention which LAMMPS version you are using.
|
||||
> **Note:** Please do not file an issue to ask a general question about LAMMPS, its features, how to use specific commands, or how perform simulations or analysis in LAMMPS. Instead post your question to either the ['lammps-users' mailing list](https://lammps.sandia.gov/mail.html) or the [LAMMPS Material Science Discourse forum](https://matsci.org/lammps). You do not need to be subscribed to post to the list (but a mailing list subscription avoids having your post delayed until it is approved by a mailing list moderator). Most posts to the mailing list receive a response within less than 24 hours. Before posting to the mailing list, please read the [mailing list guidelines](https://lammps.sandia.gov/guidelines.html). Following those guidelines will help greatly to get a helpful response. Always mention which LAMMPS version you are using. The LAMMPS forum was recently created as part of a larger effort to build a materials science community and have discussions not just about using LAMMPS. Thus the forum may be also used for discussions that would be off-topic for the mailing list. Those will just have to be moved to a more general category.
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
There are several ways how you can actively contribute to the LAMMPS project: you can discuss compiling and using LAMMPS, and solving LAMMPS related problems with other LAMMPS users on the lammps-users mailing list, you can report bugs or suggest enhancements by creating issues on GitHub (or posting them to the lammps-users mailing list), and you can contribute by submitting pull requests on GitHub or e-mail your code
|
||||
There are several ways how you can actively contribute to the LAMMPS project: you can discuss compiling and using LAMMPS, and solving LAMMPS related problems with other LAMMPS users on the lammps-users mailing list, you can report bugs or suggest enhancements by creating issues on GitHub (or posting them to the lammps-users mailing list or posting in the LAMMPS Materials Science Discourse forum), and you can contribute by submitting pull requests on GitHub or e-mail your code
|
||||
to one of the [LAMMPS core developers](https://lammps.sandia.gov/authors.html). As you may see from the aforementioned developer page, the LAMMPS software package includes the efforts of a very large number of contributors beyond the principal authors and maintainers.
|
||||
|
||||
### Discussing How To Use LAMMPS
|
||||
|
@ -42,6 +42,8 @@ Anyone can browse/search previous questions/answers in the archives. You do not
|
|||
|
||||
If you post a message and you are a subscriber, your message will appear immediately. If you are not a subscriber, your message will be moderated, which typically takes one business day. Either way, when someone replies the reply will usually be sent to both, your personal email address and the mailing list. When replying to people, that responded to your post to the list, please always included the mailing list in your replies (i.e. use "Reply All" and **not** "Reply"). Responses will appear on the list in a few minutes, but it can take a few hours for postings and replies to show up in the SourceForge archive. Sending replies also to the mailing list is important, so that responses are archived and people with a similar issue can search for possible solutions in the mailing list archive.
|
||||
|
||||
The LAMMPS Materials Science Discourse forum was created recently to facilitate discussion not just about LAMMPS and as part of a larger effort towards building a materials science community. The forum contains a read-only sub-category with the continually updated mailing list archive, so you won't miss anything by joining only the forum and not the mailing list.
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
While developers writing code for LAMMPS are careful to test their code, LAMMPS is such a large and complex software, that it is impossible to test for all combinations of features under all normal and not so normal circumstances. Thus bugs do happen, and if you suspect, that you have encountered one, please try to document it and report it as an [Issue](https://github.com/lammps/lammps/issues) on the LAMMPS GitHub project web page. However, before reporting a bug, you need to check whether this is something that may have already been corrected. The [Latest Features and Bug Fixes in LAMMPS](https://lammps.sandia.gov/bug.html) web page lists all significant changes to LAMMPS over the years. It also tells you what the current latest development version of LAMMPS is, and you should test whether your issue still applies to that version.
|
||||
|
|
|
@ -79,9 +79,11 @@ if(INTEL_ARCH STREQUAL "KNL")
|
|||
else()
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
include(CheckCXXCompilerFlag)
|
||||
foreach(_FLAG -O2 -fp-model fast=2 -no-prec-div -qoverride-limits -qopt-zmm-usage=high -qno-offload -fno-alias -ansi-alias -restrict)
|
||||
check_cxx_compiler_flag("${_FLAG}" COMPILER_SUPPORTS${_FLAG})
|
||||
if(COMPILER_SUPPORTS${_FLAG})
|
||||
foreach(_FLAG -O2 "-fp-model fast=2" -no-prec-div -qoverride-limits -qopt-zmm-usage=high -qno-offload -fno-alias -ansi-alias -restrict)
|
||||
string(REGEX REPLACE "[ =\"]" "" _FLAGX ${_FLAG})
|
||||
check_cxx_compiler_flag("${_FLAG}" COMPILER_SUPPORTS${_FLAGX})
|
||||
if(COMPILER_SUPPORTS${_FLAGX})
|
||||
separate_arguments(_FLAG UNIX_COMMAND "${_FLAG}")
|
||||
target_compile_options(lammps PRIVATE ${_FLAG})
|
||||
endif()
|
||||
endforeach()
|
||||
|
|
|
@ -17,7 +17,7 @@ if(GIT_FOUND AND EXISTS ${LAMMPS_DIR}/.git)
|
|||
ERROR_QUIET
|
||||
WORKING_DIRECTORY ${LAMMPS_DIR}
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --dirty=-modified
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --dirty=-modified --always
|
||||
OUTPUT_VARIABLE temp_git_describe
|
||||
ERROR_QUIET
|
||||
WORKING_DIRECTORY ${LAMMPS_DIR}
|
||||
|
|
|
@ -9,8 +9,8 @@ reading or writing to files with error checking or translation of
|
|||
strings into specific types of numbers with checking for validity. This
|
||||
reduces redundant implementations and encourages consistent behavior.
|
||||
|
||||
I/O with status check
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
I/O with status check and similar functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The the first two functions are wrappers around the corresponding C
|
||||
library calls ``fgets()`` or ``fread()``. They will check if there
|
||||
|
@ -19,6 +19,14 @@ In that case, the functions will stop with an error message, indicating
|
|||
the name of the problematic file, if possible unless the *error* argument
|
||||
is a NULL pointer.
|
||||
|
||||
The :cpp:func:`fgets_trunc` function will work similar for ``fgets()``
|
||||
but it will read in a whole line (i.e. until the end of line or end
|
||||
of file), but store only as many characters as will fit into the buffer
|
||||
including a final newline character and the terminating NULL byte.
|
||||
If the line in the file is longer it will thus be truncated in the buffer.
|
||||
This function is used by :cpp:func:`read_lines_from_file` to read individual
|
||||
lines but make certain they follow the size constraints.
|
||||
|
||||
The :cpp:func:`read_lines_from_file` function will read the requested
|
||||
number of lines of a maximum length into a buffer and will return 0
|
||||
if successful or 1 if not. It also guarantees that all lines are
|
||||
|
@ -33,6 +41,9 @@ NULL character.
|
|||
.. doxygenfunction:: sfread
|
||||
:project: progguide
|
||||
|
||||
.. doxygenfunction:: fgets_trunc
|
||||
:project: progguide
|
||||
|
||||
.. doxygenfunction:: read_lines_from_file
|
||||
:project: progguide
|
||||
|
||||
|
|
|
@ -223,6 +223,9 @@ The structure of the data file is important, though many settings and
|
|||
sections are optional or can come in any order. See the examples
|
||||
directory for sample data files for different problems.
|
||||
|
||||
The file will be read line by line, but there is a limit of 254
|
||||
characters per line and characters beyond that limit will be ignored.
|
||||
|
||||
A data file has a header and a body. The header appears first. The
|
||||
first line of the header is always skipped; it typically contains a
|
||||
description of the file. Then lines are read one at a time. Lines
|
||||
|
|
|
@ -363,12 +363,14 @@ variable, as discussed below.
|
|||
|
||||
The rules for formatting the file are as follows. Each time a set of
|
||||
per-atom values is read, a non-blank line is searched for in the file.
|
||||
A comment character "#" can be used anywhere on a line; text starting
|
||||
with the comment character is stripped. Blank lines are skipped. The
|
||||
first "word" of a non-blank line, delimited by white-space, is read as
|
||||
the count N of per-atom lines to immediately follow. N can be the
|
||||
total number of atoms in the system, or only a subset. The next N
|
||||
lines have the following format
|
||||
The file is read line by line but only up to 254 characters are used.
|
||||
The rest are ignored. A comment character "#" can be used anywhere
|
||||
on a line and all text following and the "#" character are ignored;
|
||||
text starting with the comment character is stripped. Blank lines
|
||||
are skipped. The first "word" of a non-blank line, delimited by
|
||||
white-space, is read as the count N of per-atom lines to immediately
|
||||
follow. N can be the total number of atoms in the system, or only a
|
||||
subset. The next N lines have the following format
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
|
|
@ -266,7 +266,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
|
|||
#if defined(MPICH) && defined(MVAPICH2_VERSION)
|
||||
char* str;
|
||||
gpu_aware_flag = 0;
|
||||
if ((str = getenv("MV2_ENABLE_CUDA")))
|
||||
if ((str = getenv("MV2_USE_CUDA")))
|
||||
if ((strcmp(str,"1") == 0))
|
||||
gpu_aware_flag = 1;
|
||||
|
||||
|
|
|
@ -155,6 +155,7 @@ ComputeChunkAtom::ComputeChunkAtom(LAMMPS *lmp, int narg, char **arg) :
|
|||
if ((which == ArgInfo::UNKNOWN) || (which == ArgInfo::NONE)
|
||||
|| (argi.get_dim() > 1))
|
||||
error->all(FLERR,"Illegal compute chunk/atom command");
|
||||
iarg = 4;
|
||||
}
|
||||
|
||||
// optional args
|
||||
|
|
|
@ -41,24 +41,25 @@
|
|||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
#define MAXLINE 256
|
||||
#define LB_FACTOR 1.1
|
||||
#define CHUNK 1024
|
||||
#define DELTA 4 // must be 2 or larger
|
||||
#define MAXBODY 32 // max # of lines in one body
|
||||
static constexpr int MAXLINE = 256;
|
||||
static constexpr double LB_FACTOR = 1.1;
|
||||
static constexpr int CHUNK = 1024;
|
||||
static constexpr int DELTA = 4; // must be 2 or larger
|
||||
static constexpr int MAXBODY = 32; // max # of lines in one body
|
||||
|
||||
// customize for new sections
|
||||
#define NSECTIONS 25 // change when add to header::section_keywords
|
||||
// customize for new sections
|
||||
// change when add to header::section_keywords
|
||||
static constexpr int NSECTIONS = 25;
|
||||
|
||||
enum{NONE,APPEND,VALUE,MERGE};
|
||||
|
||||
// pair style suffixes to ignore
|
||||
// when matching Pair Coeffs comment to currently-defined pair style
|
||||
|
||||
const char *suffixes[] = {"/cuda","/gpu","/opt","/omp","/kk",
|
||||
"/coul/cut","/coul/long","/coul/msm",
|
||||
"/coul/dsf","/coul/debye","/coul/charmm",
|
||||
nullptr};
|
||||
static const char *suffixes[] = {"/cuda","/gpu","/opt","/omp","/kk",
|
||||
"/coul/cut","/coul/long","/coul/msm",
|
||||
"/coul/dsf","/coul/debye","/coul/charmm",
|
||||
nullptr};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
|
@ -304,6 +305,12 @@ void ReadData::command(int narg, char **arg)
|
|||
extra_dihedral_types || extra_improper_types))
|
||||
error->all(FLERR,"Cannot use read_data extra with add flag");
|
||||
|
||||
// check if data file is available and readable
|
||||
|
||||
if (!utils::file_is_readable(arg[0]))
|
||||
error->all(FLERR,fmt::format("Cannot open file {}: {}",
|
||||
arg[0], utils::getsyserror()));
|
||||
|
||||
// first time system initialization
|
||||
|
||||
if (addflag == NONE) {
|
||||
|
@ -950,7 +957,7 @@ void ReadData::header(int firstpass)
|
|||
// skip 1st line of file
|
||||
|
||||
if (me == 0) {
|
||||
char *eof = fgets(line,MAXLINE,fp);
|
||||
char *eof = utils::fgets_trunc(line,MAXLINE,fp);
|
||||
if (eof == nullptr) error->one(FLERR,"Unexpected end of data file");
|
||||
}
|
||||
|
||||
|
@ -959,7 +966,7 @@ void ReadData::header(int firstpass)
|
|||
// read a line and bcast length
|
||||
|
||||
if (me == 0) {
|
||||
if (fgets(line,MAXLINE,fp) == nullptr) n = 0;
|
||||
if (utils::fgets_trunc(line,MAXLINE,fp) == nullptr) n = 0;
|
||||
else n = strlen(line) + 1;
|
||||
}
|
||||
MPI_Bcast(&n,1,MPI_INT,0,world);
|
||||
|
@ -1662,7 +1669,7 @@ void ReadData::bodies(int firstpass, AtomVec *ptr)
|
|||
m = 0;
|
||||
|
||||
while (nchunk < nmax && nline <= CHUNK-MAXBODY) {
|
||||
eof = fgets(&buffer[m],MAXLINE,fp);
|
||||
eof = utils::fgets_trunc(&buffer[m],MAXLINE,fp);
|
||||
if (eof == nullptr) error->one(FLERR,"Unexpected end of data file");
|
||||
rv = sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble);
|
||||
if (rv != 3)
|
||||
|
@ -1676,7 +1683,7 @@ void ReadData::bodies(int firstpass, AtomVec *ptr)
|
|||
|
||||
nword = 0;
|
||||
while (nword < ninteger) {
|
||||
eof = fgets(&buffer[m],MAXLINE,fp);
|
||||
eof = utils::fgets_trunc(&buffer[m],MAXLINE,fp);
|
||||
if (eof == nullptr) error->one(FLERR,"Unexpected end of data file");
|
||||
ncount = utils::trim_and_count_words(&buffer[m]);
|
||||
if (ncount == 0)
|
||||
|
@ -1690,7 +1697,7 @@ void ReadData::bodies(int firstpass, AtomVec *ptr)
|
|||
|
||||
nword = 0;
|
||||
while (nword < ndouble) {
|
||||
eof = fgets(&buffer[m],MAXLINE,fp);
|
||||
eof = utils::fgets_trunc(&buffer[m],MAXLINE,fp);
|
||||
if (eof == nullptr) error->one(FLERR,"Unexpected end of data file");
|
||||
ncount = utils::trim_and_count_words(&buffer[m]);
|
||||
if (ncount == 0)
|
||||
|
@ -1994,15 +2001,15 @@ void ReadData::parse_keyword(int first)
|
|||
|
||||
if (me == 0) {
|
||||
if (!first) {
|
||||
if (fgets(line,MAXLINE,fp) == nullptr) eof = 1;
|
||||
if (utils::fgets_trunc(line,MAXLINE,fp) == nullptr) eof = 1;
|
||||
}
|
||||
while (eof == 0 && done == 0) {
|
||||
int blank = strspn(line," \t\n\r");
|
||||
if ((blank == (int)strlen(line)) || (line[blank] == '#')) {
|
||||
if (fgets(line,MAXLINE,fp) == nullptr) eof = 1;
|
||||
if (utils::fgets_trunc(line,MAXLINE,fp) == nullptr) eof = 1;
|
||||
} else done = 1;
|
||||
}
|
||||
if (fgets(buffer,MAXLINE,fp) == nullptr) {
|
||||
if (utils::fgets_trunc(buffer,MAXLINE,fp) == nullptr) {
|
||||
eof = 1;
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
@ -2056,7 +2063,7 @@ void ReadData::skip_lines(bigint n)
|
|||
if (me) return;
|
||||
if (n <= 0) return;
|
||||
char *eof = nullptr;
|
||||
for (bigint i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp);
|
||||
for (bigint i = 0; i < n; i++) eof = utils::fgets_trunc(line,MAXLINE,fp);
|
||||
if (eof == nullptr) error->one(FLERR,"Unexpected end of data file");
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ using namespace LAMMPS_NS;
|
|||
* \param filetype Description of file type for error messages */
|
||||
|
||||
TextFileReader::TextFileReader(const std::string &filename, const std::string &filetype)
|
||||
: filename(filename), filetype(filetype), ignore_comments(true)
|
||||
: filetype(filetype), closefp(true), ignore_comments(true)
|
||||
{
|
||||
fp = fopen(filename.c_str(), "r");
|
||||
|
||||
|
@ -51,10 +51,33 @@ TextFileReader::TextFileReader(const std::string &filename, const std::string &f
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*
|
||||
\verbatim embed:rst
|
||||
|
||||
This function is useful in combination with :cpp:func:`utils::open_potential`.
|
||||
|
||||
.. note::
|
||||
|
||||
The FILE pointer is not closed in the destructor, but will be advanced
|
||||
when reading from it.
|
||||
|
||||
\endverbatim
|
||||
*
|
||||
* \param fp File descriptor of the already opened file
|
||||
* \param filetype Description of file type for error messages */
|
||||
|
||||
TextFileReader::TextFileReader(FILE *fp, const std::string &filetype)
|
||||
: filetype(filetype), closefp(false), fp(fp), ignore_comments(true)
|
||||
{
|
||||
if (fp == nullptr) throw FileReaderException("Invalid file descriptor");
|
||||
}
|
||||
|
||||
/** Closes the file */
|
||||
|
||||
TextFileReader::~TextFileReader() {
|
||||
fclose(fp);
|
||||
if (closefp) fclose(fp);
|
||||
}
|
||||
|
||||
/** Read the next line and ignore it */
|
||||
|
@ -163,5 +186,8 @@ void TextFileReader::next_dvector(double * list, int n) {
|
|||
* \return ValueTokenizer object for read in text */
|
||||
|
||||
ValueTokenizer TextFileReader::next_values(int nparams, const std::string &separators) {
|
||||
return ValueTokenizer(next_line(nparams), separators);
|
||||
char *ptr = next_line(nparams);
|
||||
if (ptr == nullptr)
|
||||
throw EOFException(fmt::format("Missing line in {} file!", filetype));
|
||||
return ValueTokenizer(line, separators);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
namespace LAMMPS_NS
|
||||
{
|
||||
class TextFileReader {
|
||||
std::string filename;
|
||||
std::string filetype;
|
||||
bool closefp;
|
||||
static constexpr int MAXLINE = 1024;
|
||||
char line[MAXLINE];
|
||||
FILE *fp;
|
||||
|
@ -35,6 +35,8 @@ namespace LAMMPS_NS
|
|||
bool ignore_comments; //!< Controls whether comments are ignored
|
||||
|
||||
TextFileReader(const std::string &filename, const std::string &filetype);
|
||||
TextFileReader(FILE *fp, const std::string &filetype);
|
||||
|
||||
~TextFileReader();
|
||||
|
||||
void skip_line();
|
||||
|
|
|
@ -68,6 +68,28 @@ Tokenizer::Tokenizer(Tokenizer && rhs) :
|
|||
reset();
|
||||
}
|
||||
|
||||
Tokenizer& Tokenizer::operator=(const Tokenizer& other)
|
||||
{
|
||||
Tokenizer tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tokenizer& Tokenizer::operator=(Tokenizer&& other)
|
||||
{
|
||||
Tokenizer tmp(std::move(other));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Tokenizer::swap(Tokenizer& other)
|
||||
{
|
||||
std::swap(text, other.text);
|
||||
std::swap(separators, other.separators);
|
||||
std::swap(start, other.start);
|
||||
std::swap(ntokens, other.ntokens);
|
||||
}
|
||||
|
||||
/*! Re-position the tokenizer state to the first word,
|
||||
* i.e. the first non-separator character */
|
||||
void Tokenizer::reset() {
|
||||
|
@ -181,6 +203,25 @@ ValueTokenizer::ValueTokenizer(const ValueTokenizer &rhs) : tokens(rhs.tokens) {
|
|||
ValueTokenizer::ValueTokenizer(ValueTokenizer &&rhs) : tokens(std::move(rhs.tokens)) {
|
||||
}
|
||||
|
||||
ValueTokenizer& ValueTokenizer::operator=(const ValueTokenizer& other)
|
||||
{
|
||||
ValueTokenizer tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueTokenizer& ValueTokenizer::operator=(ValueTokenizer&& other)
|
||||
{
|
||||
ValueTokenizer tmp(std::move(other));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ValueTokenizer::swap(ValueTokenizer& other)
|
||||
{
|
||||
std::swap(tokens, other.tokens);
|
||||
}
|
||||
|
||||
/*! Indicate whether more tokens are available
|
||||
*
|
||||
* \return true if there are more tokens, false if not */
|
||||
|
|
|
@ -37,8 +37,9 @@ public:
|
|||
Tokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
|
||||
Tokenizer(Tokenizer &&);
|
||||
Tokenizer(const Tokenizer &);
|
||||
Tokenizer& operator=(const Tokenizer&) = default;
|
||||
Tokenizer& operator=(Tokenizer&&) = default;
|
||||
Tokenizer& operator=(const Tokenizer&);
|
||||
Tokenizer& operator=(Tokenizer&&);
|
||||
void swap(Tokenizer &);
|
||||
|
||||
void reset();
|
||||
void skip(int n=1);
|
||||
|
@ -93,8 +94,9 @@ public:
|
|||
ValueTokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
|
||||
ValueTokenizer(const ValueTokenizer &);
|
||||
ValueTokenizer(ValueTokenizer &&);
|
||||
ValueTokenizer& operator=(const ValueTokenizer&) = default;
|
||||
ValueTokenizer& operator=(ValueTokenizer&&) = default;
|
||||
ValueTokenizer& operator=(const ValueTokenizer&);
|
||||
ValueTokenizer& operator=(ValueTokenizer&&);
|
||||
void swap(ValueTokenizer &);
|
||||
|
||||
std::string next_string();
|
||||
tagint next_tagint();
|
||||
|
|
|
@ -170,6 +170,42 @@ const char *utils::guesspath(char *buf, int len, FILE *fp)
|
|||
return buf;
|
||||
}
|
||||
|
||||
// read line into buffer. if line is too long keep reading until EOL or EOF
|
||||
// but return only the first part with a newline at the end.
|
||||
|
||||
char *utils::fgets_trunc(char *buf, int size, FILE *fp)
|
||||
{
|
||||
constexpr int MAXDUMMY = 256;
|
||||
char dummy[MAXDUMMY];
|
||||
char *ptr = fgets(buf,size,fp);
|
||||
|
||||
// EOF
|
||||
if (!ptr) return nullptr;
|
||||
|
||||
int n = strlen(buf);
|
||||
|
||||
// line is shorter than buffer, append newline if needed,
|
||||
if (n < size-2) {
|
||||
if (buf[n-1] != '\n') {
|
||||
buf[n] = '\n';
|
||||
buf[n+1] = '\0';
|
||||
}
|
||||
return buf;
|
||||
|
||||
// line fits exactly. overwrite last but one character.
|
||||
} else buf[size-2] = '\n';
|
||||
|
||||
// continue reading into dummy buffer until end of line or file
|
||||
do {
|
||||
ptr = fgets(dummy,MAXDUMMY,fp);
|
||||
if (ptr) n = strlen(ptr);
|
||||
else n = 0;
|
||||
} while (n == MAXDUMMY-1 && ptr[MAXDUMMY-1] != '\n');
|
||||
|
||||
// return first chunk
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define MAXPATHLENBUF 1024
|
||||
/* like fgets() but aborts with an error or EOF is encountered */
|
||||
void utils::sfgets(const char *srcname, int srcline, char *s, int size,
|
||||
|
@ -240,13 +276,12 @@ int utils::read_lines_from_file(FILE *fp, int nlines, int nmax,
|
|||
if (me == 0) {
|
||||
if (fp) {
|
||||
for (int i = 0; i < nlines; i++) {
|
||||
ptr = fgets(ptr,nmax,fp);
|
||||
ptr = fgets_trunc(ptr,nmax,fp);
|
||||
if (!ptr) break; // EOF?
|
||||
// advance ptr to end of string and append newline char if needed.
|
||||
// advance ptr to end of string
|
||||
ptr += strlen(ptr);
|
||||
if (*(--ptr) != '\n') *(++ptr) = '\n';
|
||||
// ensure buffer is null terminated. null char is start of next line.
|
||||
*(++ptr) = '\0';
|
||||
*ptr = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/utils.h
14
src/utils.h
|
@ -86,6 +86,20 @@ namespace LAMMPS_NS {
|
|||
|
||||
std::string getsyserror();
|
||||
|
||||
/** Wrapper around fgets() which reads whole lines but truncates the
|
||||
* data to the buffer size and ensures a newline char at the end.
|
||||
*
|
||||
* This function is useful for reading line based text files with
|
||||
* possible comments that should be parsed later. This applies to
|
||||
* data files, potential files, atomfile variable files and so on.
|
||||
* It is used instead of fgets() by utils::read_lines_from_file().
|
||||
*
|
||||
* \param s buffer for storing the result of fgets()
|
||||
* \param size size of buffer s (max number of bytes returned)
|
||||
* \param fp file pointer used by fgets() */
|
||||
|
||||
char *fgets_trunc(char *s, int size, FILE *fp);
|
||||
|
||||
/** Safe wrapper around fgets() which aborts on errors
|
||||
* or EOF and prints a suitable error message to help debugging.
|
||||
*
|
||||
|
|
|
@ -10,6 +10,22 @@ set_tests_properties(RunLammps PROPERTIES
|
|||
ENVIRONMENT "TSAN_OPTIONS=ignore_noninstrumented_modules=1"
|
||||
PASS_REGULAR_EXPRESSION "^LAMMPS \\([0-9]+ [A-Za-z]+ 2[0-9][0-9][0-9]\\)")
|
||||
|
||||
# check if the compiled executable will print the help message
|
||||
add_test(NAME HelpMessage
|
||||
COMMAND $<TARGET_FILE:lmp> -h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(HelpMessage PROPERTIES
|
||||
ENVIRONMENT "TSAN_OPTIONS=ignore_noninstrumented_modules=1"
|
||||
PASS_REGULAR_EXPRESSION ".*Large-scale Atomic/Molecular Massively Parallel Simulator -.*Usage example:.*")
|
||||
|
||||
# check if the compiled executable will error out on an invalid command line flag
|
||||
add_test(NAME InvalidFlag
|
||||
COMMAND $<TARGET_FILE:lmp> -xxx
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(InvalidFlag PROPERTIES
|
||||
ENVIRONMENT "TSAN_OPTIONS=ignore_noninstrumented_modules=1"
|
||||
PASS_REGULAR_EXPRESSION "ERROR: Invalid command-line argument.*")
|
||||
|
||||
if(BUILD_MPI)
|
||||
function(add_mpi_test)
|
||||
set(MPI_TEST_NUM_PROCS 1)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "lammps.h"
|
||||
|
||||
#include "citeme.h"
|
||||
#include "comm.h"
|
||||
#include "force.h"
|
||||
#include "info.h"
|
||||
#include "input.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "../testing/core.h"
|
||||
#include "../testing/utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
@ -174,6 +176,38 @@ TEST_F(SimpleCommandsTest, Partition)
|
|||
ASSERT_THAT(text, StrEq(""));
|
||||
}
|
||||
|
||||
TEST_F(SimpleCommandsTest, Processors)
|
||||
{
|
||||
// default setting is "*" for all dimensions
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[0], 0);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[1], 0);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[2], 0);
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("processors 1 1 1");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[0], 1);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[1], 1);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[2], 1);
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("processors * 1 *");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[0], 0);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[1], 1);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[2], 0);
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("processors 0 0 0");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[0], 0);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[1], 0);
|
||||
ASSERT_EQ(lmp->comm->user_procgrid[2], 0);
|
||||
|
||||
TEST_FAILURE(".*ERROR: Illegal processors command .*", command("processors -1 0 0"););
|
||||
TEST_FAILURE(".*ERROR: Specified processors != physical processors.*", command("processors 100 100 100"););
|
||||
}
|
||||
|
||||
TEST_F(SimpleCommandsTest, Quit)
|
||||
{
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
|
|
|
@ -105,8 +105,8 @@ protected:
|
|||
"# comments only\n five\n#END\n",
|
||||
fp);
|
||||
fclose(fp);
|
||||
fp = fopen("test_variable.atomfile", "w");
|
||||
|
||||
fp = fopen("test_variable.atomfile", "w");
|
||||
fputs("# test file for atomfile style variable\n\n"
|
||||
"4 # four lines\n4 0.5 #with comment\n"
|
||||
"2 -0.5 \n3 1.5\n1 -1.5\n\n"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
add_executable(test_lammps_class test_lammps_class.cpp)
|
||||
target_link_libraries(test_lammps_class PRIVATE lammps GTest::GMockMain GTest::GTest GTest::GMock)
|
||||
add_test(LammpsClass test_lammps_class)
|
||||
set_tests_properties(LammpsClass PROPERTIES ENVIRONMENT "OMP_NUM_THREADS=1")
|
||||
|
||||
add_executable(test_input_class test_input_class.cpp)
|
||||
target_link_libraries(test_input_class PRIVATE lammps GTest::GTest GTest::GTestMain)
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// unit tests for the LAMMPS base class
|
||||
|
||||
#include "comm.h"
|
||||
#include "info.h"
|
||||
#include "lammps.h"
|
||||
#include <cstdio> // for stdin, stdout
|
||||
#include <cstdio> // for stdin, stdout
|
||||
#include <cstdlib> // for setenv
|
||||
#include <mpi.h>
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using ::testing::MatchesRegex;
|
||||
using ::testing::StartsWith;
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
@ -95,6 +99,7 @@ TEST_F(LAMMPS_plain, InitMembers)
|
|||
EXPECT_STREQ(LAMMPS::git_branch, "(unknown)");
|
||||
EXPECT_STREQ(LAMMPS::git_descriptor, "(unknown)");
|
||||
}
|
||||
EXPECT_EQ(lmp->comm->nthreads, 1);
|
||||
}
|
||||
|
||||
TEST_F(LAMMPS_plain, TestStyles)
|
||||
|
@ -229,6 +234,9 @@ TEST_F(LAMMPS_omp, InitMembers)
|
|||
EXPECT_STREQ(LAMMPS::git_branch, "(unknown)");
|
||||
EXPECT_STREQ(LAMMPS::git_descriptor, "(unknown)");
|
||||
}
|
||||
#if 0 // temporarily disabled. MacOS behaves different from Linux here.
|
||||
EXPECT_EQ(lmp->comm->nthreads, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
// test fixture for Kokkos tests
|
||||
|
@ -318,10 +326,49 @@ TEST_F(LAMMPS_kokkos, InitMembers)
|
|||
}
|
||||
}
|
||||
|
||||
// check help message printing
|
||||
TEST(LAMMPS_help, HelpMessage)
|
||||
// check if Comm::nthreads is initialized to either 1 or 2 (from the previous tests)
|
||||
TEST(LAMMPS_init, OpenMP)
|
||||
{
|
||||
const char *args[] = {"LAMMPS_test", "-h"};
|
||||
if (!LAMMPS::is_installed_pkg("USER-OMP")) GTEST_SKIP();
|
||||
|
||||
FILE *fp = fopen("in.lammps_empty", "w");
|
||||
fputs("\n", fp);
|
||||
fclose(fp);
|
||||
|
||||
const char *args[] = {"LAMMPS_init", "-in", "in.lammps_empty", "-log", "none", "-nocite"};
|
||||
char **argv = (char **)args;
|
||||
int argc = sizeof(args) / sizeof(char *);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
LAMMPS *lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
|
||||
std::string output = ::testing::internal::GetCapturedStdout();
|
||||
EXPECT_THAT(output, MatchesRegex(".*using 2 OpenMP thread.*per MPI task.*"));
|
||||
|
||||
if (LAMMPS_NS::Info::has_accelerator_feature("USER-OMP", "api", "openmp"))
|
||||
EXPECT_EQ(lmp->comm->nthreads, 2);
|
||||
else
|
||||
EXPECT_EQ(lmp->comm->nthreads, 1);
|
||||
::testing::internal::CaptureStdout();
|
||||
delete lmp;
|
||||
::testing::internal::GetCapturedStdout();
|
||||
|
||||
remove("in.lammps_empty");
|
||||
}
|
||||
|
||||
// check no OMP_NUM_THREADS warning message printing. this must be the
|
||||
// last OpenMP related test as threads will be locked to 1 from here on.
|
||||
|
||||
TEST(LAMMPS_init, NoOpenMP)
|
||||
{
|
||||
if (!LAMMPS_NS::Info::has_accelerator_feature("USER-OMP", "api", "openmp"))
|
||||
GTEST_SKIP() << "No threading enabled";
|
||||
|
||||
FILE *fp = fopen("in.lammps_class_noomp", "w");
|
||||
fputs("\n", fp);
|
||||
fclose(fp);
|
||||
unsetenv("OMP_NUM_THREADS");
|
||||
|
||||
const char *args[] = {"LAMMPS_init", "-in", "in.lammps_class_noomp", "-log", "none", "-nocite"};
|
||||
char **argv = (char **)args;
|
||||
int argc = sizeof(args) / sizeof(char *);
|
||||
|
||||
|
@ -329,7 +376,11 @@ TEST(LAMMPS_help, HelpMessage)
|
|||
LAMMPS *lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
|
||||
std::string output = ::testing::internal::GetCapturedStdout();
|
||||
EXPECT_THAT(output,
|
||||
StartsWith("\nLarge-scale Atomic/Molecular Massively Parallel Simulator -"));
|
||||
MatchesRegex(".*OMP_NUM_THREADS environment is not set.*Defaulting to 1 thread.*"));
|
||||
EXPECT_EQ(lmp->comm->nthreads, 1);
|
||||
::testing::internal::CaptureStdout();
|
||||
delete lmp;
|
||||
::testing::internal::GetCapturedStdout();
|
||||
}
|
||||
|
||||
} // namespace LAMMPS_NS
|
||||
|
|
|
@ -33,7 +33,7 @@ else()
|
|||
target_link_libraries(style_tests PUBLIC mpi_stubs)
|
||||
endif()
|
||||
# propagate sanitizer options to test tools
|
||||
if (NOT ENABLE_SANITIZER STREQUAL "none")
|
||||
if (ENABLE_SANITIZER AND (NOT ENABLE_SANITIZER STREQUAL "none"))
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
|
||||
target_compile_options(style_tests PUBLIC -fsanitize=${ENABLE_SANITIZER})
|
||||
target_link_options(style_tests PUBLIC -fsanitize=${ENABLE_SANITIZER})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
lammps_version: 10 Feb 2021
|
||||
date_generated: Fri Feb 26 23:09:10 2021
|
||||
epsilon: 5e-14
|
||||
epsilon: 2e-13
|
||||
prerequisites: ! |
|
||||
atom sphere
|
||||
pair yukawa/colloid
|
||||
|
|
|
@ -28,6 +28,11 @@ if(PKG_MANYBODY)
|
|||
set_tests_properties(EIMPotentialFileReader PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
endif()
|
||||
|
||||
add_executable(test_text_file_reader test_text_file_reader.cpp)
|
||||
target_link_libraries(test_text_file_reader PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME TextFileReader COMMAND test_text_file_reader WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(TextFileReader PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
|
||||
add_executable(test_file_operations test_file_operations.cpp)
|
||||
target_link_libraries(test_file_operations PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME FileOperations COMMAND test_file_operations WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
|
|
@ -75,6 +75,31 @@ TEST_F(DumpCfgTest, run0)
|
|||
delete_file("dump_cfg_run0.melt.cfg");
|
||||
}
|
||||
|
||||
TEST_F(DumpCfgTest, write_dump)
|
||||
{
|
||||
auto dump_file = "dump_cfg_run*.melt.cfg";
|
||||
auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz";
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command(std::string("write_dump all cfg dump_cfg.melt.cfg ") + fields);
|
||||
command(std::string("write_dump all cfg dump_cfg*.melt.cfg ") + fields);
|
||||
END_HIDE_OUTPUT();
|
||||
|
||||
ASSERT_FILE_EXISTS("dump_cfg.melt.cfg");
|
||||
auto lines = read_lines("dump_cfg.melt.cfg");
|
||||
ASSERT_EQ(lines.size(), 124);
|
||||
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
|
||||
delete_file("dump_cfg.melt.cfg");
|
||||
|
||||
ASSERT_FILE_EXISTS("dump_cfg0.melt.cfg");
|
||||
lines = read_lines("dump_cfg0.melt.cfg");
|
||||
ASSERT_EQ(lines.size(), 124);
|
||||
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
|
||||
delete_file("dump_cfg0.melt.cfg");
|
||||
|
||||
TEST_FAILURE(".*ERROR: Unrecognized dump style 'xxx'.*", command("write_dump all xxx test.xxx"););
|
||||
}
|
||||
|
||||
TEST_F(DumpCfgTest, unwrap_run0)
|
||||
{
|
||||
auto dump_file = "dump_cfg_unwrap_run*.melt.cfg";
|
||||
|
|
|
@ -12,11 +12,14 @@
|
|||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "../testing/core.h"
|
||||
#include "../testing/utils.h"
|
||||
#include "atom.h"
|
||||
#include "domain.h"
|
||||
#include "error.h"
|
||||
#include "info.h"
|
||||
#include "input.h"
|
||||
#include "lammps.h"
|
||||
#include "utils.h"
|
||||
#include "update.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
@ -45,19 +48,29 @@ protected:
|
|||
LAMMPSTest::SetUp();
|
||||
ASSERT_NE(lmp, nullptr);
|
||||
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "wb");
|
||||
ASSERT_NE(fp, nullptr);
|
||||
fputs("one line\n", fp);
|
||||
fputs("two_lines\n", fp);
|
||||
fputs("\n", fp);
|
||||
fputs("no newline", fp);
|
||||
fclose(fp);
|
||||
std::ofstream out("safe_file_read_test.txt", std::ios_base::out | std::ios_base::binary);
|
||||
ASSERT_TRUE(out.good());
|
||||
out << "one line\ntwo_lines\n\nno newline";
|
||||
out.close();
|
||||
|
||||
out.open("file_with_long_lines_test.txt", std::ios_base::out | std::ios_base::binary);
|
||||
ASSERT_TRUE(out.good());
|
||||
out << "zero ##########################################################"
|
||||
"##################################################################"
|
||||
"##################################################################"
|
||||
"############################################################\n";
|
||||
out << "one line\ntwo_lines\n\n";
|
||||
for (int i = 0; i < 100; ++i) out << "one two ";
|
||||
out << "\nthree\nfour five #";
|
||||
for (int i = 0; i < 1000; ++i) out << '#';
|
||||
out.close();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
LAMMPSTest::TearDown();
|
||||
remove("safe_file_read_test.txt");
|
||||
remove("file_with_long_lines_test.txt");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -66,7 +79,7 @@ TEST_F(FileOperationsTest, safe_fgets)
|
|||
{
|
||||
char buf[MAX_BUF_SIZE];
|
||||
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "r");
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "rb");
|
||||
ASSERT_NE(fp, nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
|
@ -97,12 +110,74 @@ TEST_F(FileOperationsTest, safe_fgets)
|
|||
fclose(fp);
|
||||
}
|
||||
|
||||
#define MAX_BUF_SIZE 128
|
||||
TEST_F(FileOperationsTest, fgets_trunc)
|
||||
{
|
||||
char buf[MAX_BUF_SIZE];
|
||||
char *ptr;
|
||||
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "rb");
|
||||
ASSERT_NE(fp, nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("one line\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("two_lines\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
ptr = utils::fgets_trunc(buf, 4, fp);
|
||||
ASSERT_THAT(buf, StrEq("no\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_EQ(ptr,nullptr);
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen("file_with_long_lines_test.txt", "r");
|
||||
ASSERT_NE(fp,nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
ASSERT_THAT(buf, StrEq("zero ##########################################################"
|
||||
"###############################################################\n"));
|
||||
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("one line\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("two_lines\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_THAT(buf, StrEq("\n"));
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
|
||||
ptr = utils::fgets_trunc(buf, MAX_BUF_SIZE, fp);
|
||||
ASSERT_NE(ptr,nullptr);
|
||||
ASSERT_THAT(buf, StrEq("one two one two one two one two one two one two one two one two "
|
||||
"one two one two one two one two one two one two one two one tw\n"));
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
#define MAX_BUF_SIZE 128
|
||||
TEST_F(FileOperationsTest, safe_fread)
|
||||
{
|
||||
char buf[MAX_BUF_SIZE];
|
||||
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "r");
|
||||
FILE *fp = fopen("safe_file_read_test.txt", "rb");
|
||||
ASSERT_NE(fp, nullptr);
|
||||
|
||||
memset(buf, 0, MAX_BUF_SIZE);
|
||||
|
@ -128,7 +203,7 @@ TEST_F(FileOperationsTest, safe_fread)
|
|||
|
||||
TEST_F(FileOperationsTest, read_lines_from_file)
|
||||
{
|
||||
char *buf = new char[MAX_BUF_SIZE];
|
||||
char *buf = new char[MAX_BUF_SIZE];
|
||||
FILE *fp = nullptr;
|
||||
MPI_Comm world = MPI_COMM_WORLD;
|
||||
int me, rv;
|
||||
|
@ -225,6 +300,191 @@ TEST_F(FileOperationsTest, error_all_one)
|
|||
lmp->error->one("testme.cpp", 10, "exit {} {}", "too"););
|
||||
}
|
||||
|
||||
TEST_F(FileOperationsTest, write_restart)
|
||||
{
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("echo none");
|
||||
END_HIDE_OUTPUT();
|
||||
TEST_FAILURE(".*ERROR: Write_restart command before simulation box is defined.*",
|
||||
command("write_restart test.restart"););
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("region box block -2 2 -2 2 -2 2");
|
||||
command("create_box 1 box");
|
||||
command("create_atoms 1 single 0.0 0.0 0.0");
|
||||
command("mass 1 1.0");
|
||||
command("reset_timestep 333");
|
||||
command("comm_modify cutoff 0.2");
|
||||
command("write_restart noinit.restart noinit");
|
||||
command("run 0 post no");
|
||||
command("write_restart test.restart");
|
||||
command("write_restart step*.restart");
|
||||
command("write_restart multi-%.restart");
|
||||
command("write_restart multi2-%.restart fileper 2");
|
||||
command("write_restart multi3-%.restart nfile 1");
|
||||
if (info->has_package("MPIIO")) command("write_restart test.restart.mpiio");
|
||||
END_HIDE_OUTPUT();
|
||||
|
||||
ASSERT_FILE_EXISTS("noinit.restart");
|
||||
ASSERT_FILE_EXISTS("test.restart");
|
||||
ASSERT_FILE_EXISTS("step333.restart");
|
||||
ASSERT_FILE_EXISTS("multi-base.restart");
|
||||
ASSERT_FILE_EXISTS("multi-0.restart");
|
||||
ASSERT_FILE_EXISTS("multi2-base.restart");
|
||||
ASSERT_FILE_EXISTS("multi2-0.restart");
|
||||
ASSERT_FILE_EXISTS("multi3-base.restart");
|
||||
ASSERT_FILE_EXISTS("multi3-0.restart");
|
||||
if (info->has_package("MPIIO")) ASSERT_FILE_EXISTS("test.restart.mpiio");
|
||||
|
||||
if (!info->has_package("MPIIO")) {
|
||||
TEST_FAILURE(".*ERROR: Writing to MPI-IO filename when MPIIO package is not inst.*",
|
||||
command("write_restart test.restart.mpiio"););
|
||||
} else {
|
||||
TEST_FAILURE(".*ERROR: Restart file MPI-IO output not allowed with % in filename.*",
|
||||
command("write_restart test.restart-%.mpiio"););
|
||||
}
|
||||
|
||||
TEST_FAILURE(".*ERROR: Illegal write_restart command.*", command("write_restart"););
|
||||
TEST_FAILURE(".*ERROR: Illegal write_restart command.*",
|
||||
command("write_restart test.restart xxxx"););
|
||||
TEST_FAILURE(".*ERROR on proc 0: Cannot open restart file some_crazy_dir/test.restart:"
|
||||
" No such file or directory.*",
|
||||
command("write_restart some_crazy_dir/test.restart"););
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("clear");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 0);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 0);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 0);
|
||||
|
||||
TEST_FAILURE(
|
||||
".*ERROR on proc 0: Cannot open restart file noexist.restart: No such file or directory.*",
|
||||
command("read_restart noexist.restart"););
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("read_restart step333.restart");
|
||||
command("change_box all triclinic");
|
||||
command("write_restart triclinic.restart");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 1);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 333);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 1);
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("clear");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 0);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 0);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 0);
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("read_restart triclinic.restart");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 1);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 333);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 1);
|
||||
|
||||
// clean up
|
||||
delete_file("noinit.restart");
|
||||
delete_file("test.restart");
|
||||
delete_file("step333.restart");
|
||||
delete_file("multi-base.restart");
|
||||
delete_file("multi-0.restart");
|
||||
delete_file("multi2-base.restart");
|
||||
delete_file("multi2-0.restart");
|
||||
delete_file("multi3-base.restart");
|
||||
delete_file("multi3-0.restart");
|
||||
delete_file("triclinic.restart");
|
||||
if (info->has_package("MPIIO")) delete_file("test.restart.mpiio");
|
||||
}
|
||||
|
||||
TEST_F(FileOperationsTest, write_data)
|
||||
{
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("echo none");
|
||||
END_HIDE_OUTPUT();
|
||||
TEST_FAILURE(".*ERROR: Write_data command before simulation box is defined.*",
|
||||
command("write_data test.data"););
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("region box block -2 2 -2 2 -2 2");
|
||||
command("create_box 2 box");
|
||||
command("create_atoms 1 single 0.5 0.0 0.0");
|
||||
command("pair_style zero 1.0");
|
||||
command("pair_coeff * *");
|
||||
command("mass * 1.0");
|
||||
command("reset_timestep 333");
|
||||
command("write_data noinit.data noinit");
|
||||
command("write_data nocoeff.data nocoeff");
|
||||
command("run 0 post no");
|
||||
command("write_data test.data");
|
||||
command("write_data step*.data pair ij");
|
||||
command("fix q all property/atom q");
|
||||
command("set type 1 charge -0.5");
|
||||
command("write_data charge.data");
|
||||
command("write_data nofix.data nofix");
|
||||
END_HIDE_OUTPUT();
|
||||
|
||||
ASSERT_FILE_EXISTS("noinit.data");
|
||||
ASSERT_EQ(count_lines("noinit.data"), 26);
|
||||
ASSERT_FILE_EXISTS("test.data");
|
||||
ASSERT_EQ(count_lines("test.data"), 26);
|
||||
ASSERT_FILE_EXISTS("step333.data");
|
||||
ASSERT_EQ(count_lines("step333.data"), 27);
|
||||
ASSERT_FILE_EXISTS("nocoeff.data");
|
||||
ASSERT_EQ(count_lines("nocoeff.data"), 21);
|
||||
ASSERT_FILE_EXISTS("nofix.data");
|
||||
ASSERT_EQ(count_lines("nofix.data"), 26);
|
||||
ASSERT_FILE_EXISTS("charge.data");
|
||||
ASSERT_EQ(count_lines("charge.data"), 30);
|
||||
|
||||
TEST_FAILURE(".*ERROR: Illegal write_data command.*", command("write_data"););
|
||||
TEST_FAILURE(".*ERROR: Illegal write_data command.*", command("write_data test.data xxxx"););
|
||||
TEST_FAILURE(".*ERROR: Illegal write_data command.*", command("write_data test.data pair xx"););
|
||||
TEST_FAILURE(".*ERROR on proc 0: Cannot open data file some_crazy_dir/test.data:"
|
||||
" No such file or directory.*",
|
||||
command("write_data some_crazy_dir/test.data"););
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("clear");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->domain->box_exist, 0);
|
||||
ASSERT_EQ(lmp->atom->natoms, 0);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 0);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 0);
|
||||
|
||||
TEST_FAILURE(".*ERROR: Cannot open file noexist.data: No such file or directory.*",
|
||||
command("read_data noexist.data"););
|
||||
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("pair_style zero 1.0");
|
||||
command("read_data step333.data");
|
||||
command("change_box all triclinic");
|
||||
command("write_data triclinic.data");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 1);
|
||||
ASSERT_EQ(lmp->update->ntimestep, 0);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 1);
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("clear");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 0);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 0);
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("pair_style zero 1.0");
|
||||
command("read_data triclinic.data");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(lmp->atom->natoms, 1);
|
||||
ASSERT_EQ(lmp->domain->triclinic, 1);
|
||||
|
||||
// clean up
|
||||
delete_file("charge.data");
|
||||
delete_file("nocoeff.data");
|
||||
delete_file("noinit.data");
|
||||
delete_file("nofix.data");
|
||||
delete_file("test.data");
|
||||
delete_file("step333.data");
|
||||
delete_file("triclinic.data");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/* ----------------------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
https://lammps.sandia.gov/, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "info.h"
|
||||
#include "input.h"
|
||||
#include "text_file_reader.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "../testing/core.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mpi.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
using LAMMPS_NS::utils::split_words;
|
||||
|
||||
// whether to print verbose output (i.e. not capturing LAMMPS screen output).
|
||||
bool verbose = false;
|
||||
|
||||
class TextFileReaderTest : public ::testing::Test {
|
||||
|
||||
protected:
|
||||
void TearDown() override
|
||||
{
|
||||
unlink("text_reader_one.file");
|
||||
unlink("text_reader_two.file");
|
||||
}
|
||||
|
||||
void test_files()
|
||||
{
|
||||
FILE *fp = fopen("text_reader_one.file", "w");
|
||||
fputs("# test file 1 for text file reader\n\n\none\n two \n\n"
|
||||
"three # with comment\nfour ! with non-comment\n"
|
||||
"# comments only\n five\n#END\n",
|
||||
fp);
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen("text_reader_two.file", "w");
|
||||
fputs("# test file for atomfile style variable\n\n"
|
||||
"4 # four lines\n4 0.5 #with comment\n"
|
||||
"2 -0.5 \n3 1.5\n1 -1.5\n\n"
|
||||
"2\n10 1.0 # test\n13 1.0\n\n######\n"
|
||||
"4\n1 4.0 # test\n2 3.0\n3 2.0\n4 1.0\n#END\n",
|
||||
fp);
|
||||
fclose(fp);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TextFileReaderTest, nofile)
|
||||
{
|
||||
ASSERT_THROW({ TextFileReader reader("text_reader_noexist.file", "test"); },
|
||||
FileReaderException);
|
||||
}
|
||||
|
||||
TEST_F(TextFileReaderTest, permissions)
|
||||
{
|
||||
FILE *fp = fopen("text_reader_noperms.file", "w");
|
||||
fputs("word\n", fp);
|
||||
fclose(fp);
|
||||
chmod("text_reader_noperms.file", 0);
|
||||
ASSERT_THROW({ TextFileReader reader("text_reader_noperms.file", "test"); },
|
||||
FileReaderException);
|
||||
unlink("text_reader_noperms.file");
|
||||
}
|
||||
|
||||
TEST_F(TextFileReaderTest, nofp)
|
||||
{
|
||||
ASSERT_THROW({ TextFileReader reader(nullptr, "test"); },
|
||||
FileReaderException);
|
||||
}
|
||||
|
||||
TEST_F(TextFileReaderTest, usefp)
|
||||
{
|
||||
test_files();
|
||||
FILE *fp = fopen("text_reader_two.file","r");
|
||||
ASSERT_NE(fp,nullptr);
|
||||
|
||||
auto reader = new TextFileReader(fp, "test");
|
||||
auto line = reader->next_line();
|
||||
ASSERT_STREQ(line, "4 ");
|
||||
line = reader->next_line(1);
|
||||
ASSERT_STREQ(line, "4 0.5 ");
|
||||
ASSERT_NO_THROW({ reader->skip_line(); });
|
||||
auto values = reader->next_values(1);
|
||||
ASSERT_EQ(values.count(), 2);
|
||||
ASSERT_EQ(values.next_int(), 3);
|
||||
ASSERT_STREQ(values.next_string().c_str(), "1.5");
|
||||
ASSERT_NE(reader->next_line(), nullptr);
|
||||
double data[20];
|
||||
ASSERT_THROW({ reader->next_dvector(data,20); }, FileReaderException);
|
||||
ASSERT_THROW({ reader->skip_line(); }, EOFException);
|
||||
ASSERT_EQ(reader->next_line(), nullptr);
|
||||
delete reader;
|
||||
|
||||
// check that we reached EOF and the destructor didn't close the file.
|
||||
ASSERT_EQ(feof(fp),1);
|
||||
ASSERT_EQ(fclose(fp),0);
|
||||
}
|
||||
|
||||
TEST_F(TextFileReaderTest, comments)
|
||||
{
|
||||
test_files();
|
||||
TextFileReader reader("text_reader_two.file", "test");
|
||||
reader.ignore_comments = true;
|
||||
auto line = reader.next_line();
|
||||
ASSERT_STREQ(line, "4 ");
|
||||
line = reader.next_line(1);
|
||||
ASSERT_STREQ(line, "4 0.5 ");
|
||||
ASSERT_NO_THROW({ reader.skip_line(); });
|
||||
auto values = reader.next_values(1);
|
||||
ASSERT_EQ(values.count(), 2);
|
||||
ASSERT_EQ(values.next_int(), 3);
|
||||
ASSERT_STREQ(values.next_string().c_str(), "1.5");
|
||||
ASSERT_NE(reader.next_line(), nullptr);
|
||||
double data[20];
|
||||
ASSERT_THROW({ reader.next_dvector(data,20); }, FileReaderException);
|
||||
ASSERT_THROW({ reader.skip_line(); }, EOFException);
|
||||
ASSERT_EQ(reader.next_line(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(TextFileReaderTest, nocomments)
|
||||
{
|
||||
test_files();
|
||||
TextFileReader reader("text_reader_one.file", "test");
|
||||
reader.ignore_comments = false;
|
||||
auto line = reader.next_line();
|
||||
ASSERT_STREQ(line, "# test file 1 for text file reader\n");
|
||||
line = reader.next_line(1);
|
||||
ASSERT_STREQ(line, "one\n");
|
||||
ASSERT_NO_THROW({ reader.skip_line(); });
|
||||
auto values = reader.next_values(4);
|
||||
ASSERT_EQ(values.count(), 4);
|
||||
ASSERT_STREQ(values.next_string().c_str(), "three");
|
||||
ASSERT_STREQ(values.next_string().c_str(), "#");
|
||||
ASSERT_STREQ(values.next_string().c_str(), "with");
|
||||
try {
|
||||
reader.next_values(100);
|
||||
FAIL() << "No exception thrown\n";
|
||||
} catch (EOFException &e) {
|
||||
ASSERT_STREQ(e.what(), "Incorrect format in test file! 9/100 parameters");
|
||||
}
|
||||
ASSERT_THROW({ reader.skip_line(); }, EOFException);
|
||||
ASSERT_EQ(reader.next_line(), nullptr);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MPI_Init(&argc, &argv);
|
||||
::testing::InitGoogleMock(&argc, argv);
|
||||
|
||||
if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
|
||||
std::cout << "Warning: using OpenMPI without exceptions. "
|
||||
"Death tests will be skipped\n";
|
||||
|
||||
// handle arguments passed via environment variable
|
||||
if (const char *var = getenv("TEST_ARGS")) {
|
||||
std::vector<std::string> env = split_words(var);
|
||||
for (auto arg : env) {
|
||||
if (arg == "-v") {
|
||||
verbose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true;
|
||||
|
||||
int rv = RUN_ALL_TESTS();
|
||||
MPI_Finalize();
|
||||
return rv;
|
||||
}
|
|
@ -10,14 +10,12 @@
|
|||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
#ifndef TEST_EXTENSIONS__H
|
||||
#define TEST_EXTENSIONS__H
|
||||
#ifndef LMP_TESTING_UTILS_H
|
||||
#define LMP_TESTING_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <vector>
|
||||
|
||||
static void delete_file(const std::string &filename)
|
||||
|
@ -65,8 +63,8 @@ static std::vector<std::string> read_lines(const std::string &filename)
|
|||
|
||||
static bool file_exists(const std::string &filename)
|
||||
{
|
||||
struct stat result;
|
||||
return stat(filename.c_str(), &result) == 0;
|
||||
std::ifstream infile(filename);
|
||||
return infile.good();
|
||||
}
|
||||
|
||||
#define ASSERT_FILE_EXISTS(NAME) ASSERT_TRUE(file_exists(NAME))
|
||||
|
|
|
@ -53,6 +53,11 @@ TEST(Tokenizer, skip)
|
|||
ASSERT_FALSE(t.has_next());
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
ASSERT_THROW(t.skip(), TokenizerException);
|
||||
try {
|
||||
t.skip();
|
||||
} catch (TokenizerException &e) {
|
||||
ASSERT_STREQ(e.what(), "No more tokens");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Tokenizer, prefix_separators)
|
||||
|
@ -87,6 +92,47 @@ TEST(Tokenizer, copy_constructor)
|
|||
ASSERT_EQ(u.count(), 2);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, move_constructor)
|
||||
{
|
||||
Tokenizer u = std::move(Tokenizer("test new word ", " "));
|
||||
ASSERT_THAT(u.next(), Eq("test"));
|
||||
ASSERT_THAT(u.next(), Eq("new"));
|
||||
ASSERT_THAT(u.next(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, copy_assignment)
|
||||
{
|
||||
Tokenizer t(" test word ", " ");
|
||||
Tokenizer u(" test2 word2 other2 ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
Tokenizer v = u;
|
||||
u = t;
|
||||
ASSERT_THAT(u.next(), Eq("test"));
|
||||
ASSERT_THAT(u.next(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 2);
|
||||
|
||||
ASSERT_THAT(v.next(), Eq("test2"));
|
||||
ASSERT_THAT(v.next(), Eq("word2"));
|
||||
ASSERT_THAT(v.next(), Eq("other2"));
|
||||
ASSERT_EQ(v.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, move_assignment)
|
||||
{
|
||||
Tokenizer t(" test word ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
t = Tokenizer("test new word ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("new"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, no_separator_path)
|
||||
{
|
||||
Tokenizer t("one", ":");
|
||||
|
@ -181,12 +227,72 @@ TEST(ValueTokenizer, skip)
|
|||
ASSERT_FALSE(t.has_next());
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
ASSERT_THROW(t.skip(), TokenizerException);
|
||||
try {
|
||||
t.skip();
|
||||
} catch (TokenizerException &e) {
|
||||
ASSERT_STREQ(e.what(), "No more tokens");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, copy_constructor)
|
||||
{
|
||||
ValueTokenizer t(" test word ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
ValueTokenizer u(t);
|
||||
ASSERT_THAT(u.next_string(), Eq("test"));
|
||||
ASSERT_THAT(u.next_string(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 2);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, move_constructor)
|
||||
{
|
||||
ValueTokenizer u = std::move(ValueTokenizer(" test new word ", " "));
|
||||
ASSERT_THAT(u.next_string(), Eq("test"));
|
||||
ASSERT_THAT(u.next_string(), Eq("new"));
|
||||
ASSERT_THAT(u.next_string(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, copy_assignment)
|
||||
{
|
||||
ValueTokenizer t(" test word ", " ");
|
||||
ValueTokenizer u(" test2 word2 other2 ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
ValueTokenizer v = u;
|
||||
u = t;
|
||||
ASSERT_THAT(u.next_string(), Eq("test"));
|
||||
ASSERT_THAT(u.next_string(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 2);
|
||||
|
||||
ASSERT_THAT(v.next_string(), Eq("test2"));
|
||||
ASSERT_THAT(v.next_string(), Eq("word2"));
|
||||
ASSERT_THAT(v.next_string(), Eq("other2"));
|
||||
ASSERT_EQ(v.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, move_assignment)
|
||||
{
|
||||
ValueTokenizer t(" test word ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
t = ValueTokenizer("test new word ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("new"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, bad_integer)
|
||||
{
|
||||
ValueTokenizer values("f10");
|
||||
ValueTokenizer values("f10 f11 f12");
|
||||
ASSERT_THROW(values.next_int(), InvalidIntegerException);
|
||||
ASSERT_THROW(values.next_bigint(), InvalidIntegerException);
|
||||
ASSERT_THROW(values.next_tagint(), InvalidIntegerException);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, bad_double)
|
||||
|
|
Loading…
Reference in New Issue