diff --git a/src/coreComponents/codingUtilities/RTTypes.cpp b/src/coreComponents/codingUtilities/RTTypes.cpp index 648f94e6b31..415a494b1d4 100644 --- a/src/coreComponents/codingUtilities/RTTypes.cpp +++ b/src/coreComponents/codingUtilities/RTTypes.cpp @@ -151,7 +151,7 @@ rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() // string_view const ru = "[\\d]+";// unused string_view const intDesc = "Input value must be a signed int (eg. -123, 455, +789, etc.)"; - string_view const intRegex = "[+-]?[\\d]+"; + string_view const intRegex = "\\s*[+-]?[\\d]+\\s*"; // Explanation of parts: // [+-]?[\\d]* matches an optional +/- at the beginning, any numbers preceding the decimal @@ -160,7 +160,7 @@ rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() // ([eE][-+]?[\\d]+|\\s*) matches an optional scientific notation number // Note: the xsd regex implementation does not allow an empty branch, so use allow whitespace at the end string_view const realDesc = "Input value must be a real number (eg. 1, .25, +2.3, -.4, 5.6e7, -8E-9, etc.)"; - string_view const realRegex = "[+-]?[\\d]*([\\d]\\.?|\\.[\\d])[\\d]*([eE][-+]?[\\d]+|\\s*)"; + string_view const realRegex = "\\s*[+-]?[\\d]*([\\d]\\.?|\\.[\\d])[\\d]*([eE][-+]?[\\d]+|\\s*)"; string_view const R1Desc = "Input value must be a R1Tensor, an array of 3 real numbers surrounded by braces and separated by commas (eg. \"{ 1, .25, +2.3}\", \"{ -.4, 5.6e7, -8E-9\", etc.) ."; string const R1Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){2}" + string( realRegex ) + "\\s*\\}\\s*"; @@ -168,20 +168,23 @@ rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() string const R2Regex = "\\s*\\{\\s*(" + string( realRegex ) + "\\s*,\\s*){5}" + string( realRegex ) + "\\s*\\}\\s*"; string_view const strDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters , { }"; - string_view const strRegex = "[^,\\{\\}\\s]+\\s*"; + string_view const strRegex = "\\s*[^,\\{\\}\\s]+\\s*"; string_view const strEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters , { }"; - string_view const strERegex = "[^,\\{\\}\\s]*\\s*"; + string_view const strERegex = "\\s*[^,\\{\\}\\s]*\\s*"; string_view const pathDesc = "Input value must be a string that cannot be empty, contain any whitespaces nor the characters * ? < > | : \" "; - string_view const pathRegex = "[^*?<>\\|:\";,\\s]+\\s*"; + string_view const pathRegex = "\\s*[^*?<>\\|:\";,\\s]+\\s*"; string_view const pathEDesc = "Input value must be a string that cannot contain any whitespaces nor the characters * ? < > | : \" "; - string_view const pathERegex = "[^*?<>\\|:\";,\\s]*\\s*"; + string_view const pathERegex = "\\s*[^*?<>\\|:\";,\\s]*\\s*"; string_view const groupNameDesc = "Input value must be a string that cannot be empty and contains only upper/lower letters, digits, and the characters . - _"; - string_view const groupNameRegex = "[a-zA-Z0-9.\\-_]+"; + string_view const groupNameRegex = "\\s*[a-zA-Z0-9.\\-_]+\\s*"; // to reference groups, we need to support the / for paths, and * [ ] for fnmatch patterns. string_view const groupNameRefDesc = "Input value must be a string that can contain only upper/lower letters, digits, and the characters . - _ / * [ ]"; - string_view const groupNameRefRegex = "[a-zA-Z0-9.\\-_/*\\[\\]]*"; + string_view const groupNameRefRegex = "\\s*[a-zA-Z0-9.\\-_/*\\[\\]]*\\s*"; + // to reference an array of groups, we need to support the / for paths, and * [ ] for fnmatch patterns. + string_view const groupNameRefArrayDesc = "Input value must be a list of strings that can contain only upper/lower letters, digits, and the characters . - _ / * [ ]"; + string_view const groupNameRefArrayRegex = "\\s*\\{([a-zA-Z0-9.\\-_/*\\[\\], ]+)*\\}\\s*"; // Build master list of regexes @@ -220,7 +223,7 @@ rtTypes::RegexMapType rtTypes::createBasicTypesRegexMap() { string( CustomTypes::plotLevel ), Regex( intRegex, intDesc ) }, { string( CustomTypes::groupName ), Regex( groupNameRegex, groupNameDesc ) }, { string( CustomTypes::groupNameRef ), Regex( groupNameRefRegex, groupNameRefDesc ) }, - { string( CustomTypes::groupNameRefArray ), constructArrayRegex( groupNameRefRegex, groupNameRefDesc, 1 ) } + { string( CustomTypes::groupNameRefArray ), Regex( groupNameRefArrayRegex, groupNameRefArrayDesc ) } }; return regexMap; } diff --git a/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp b/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp index 087eaf546be..948f6cc7224 100644 --- a/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp +++ b/src/coreComponents/dataRepository/unitTests/testXmlWrapper.cpp @@ -243,6 +243,9 @@ INSTANTIATE_TEST_SUITE_P( real64AttributeTests, real64AttributeTestFixture, ::testing::Values( std::make_tuple( "1", 1, false ), + std::make_tuple( "1 ", 1, false ), + std::make_tuple( " 1", 1, false ), + std::make_tuple( " 1 ", 1, false ), std::make_tuple( "-23", -23, false ), std::make_tuple( "4.5", 4.5, false ), std::make_tuple( "4.", 4.0, false ), @@ -260,7 +263,6 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple( "1.234gamma", 0, true ), std::make_tuple( "1.2.3", 0, true ), std::make_tuple( "1e2.3 ", 0, true ), - std::make_tuple( "1 ", 0, true ), std::make_tuple( "1e", 0, true ), std::make_tuple( "1e-", 0, true ), std::make_tuple( "1e+", 0, true ))); @@ -284,6 +286,9 @@ INSTANTIATE_TEST_SUITE_P( real32AttributeTests, real32AttributeTestFixture, ::testing::Values( std::make_tuple( "1", 1, false ), + std::make_tuple( "1 ", 1, false ), + std::make_tuple( " 1", 1, false ), + std::make_tuple( " 1 ", 1, false ), std::make_tuple( "-23", -23, false ), std::make_tuple( "4.5", 4.5, false ), std::make_tuple( "4.", 4.0, false ), @@ -301,7 +306,6 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple( "1.234gamma", 0, true ), std::make_tuple( "1.2.3", 0, true ), std::make_tuple( "1e2.3 ", 0, true ), - std::make_tuple( "1 ", 0, true ), std::make_tuple( "1e", 0, true ), std::make_tuple( "1e-", 0, true ), std::make_tuple( "1e+", 0, true ))); @@ -319,13 +323,15 @@ INSTANTIATE_TEST_SUITE_P( integerAttributeTests, integerAttributeTestFixture, ::testing::Values( std::make_tuple( "1", 1, false ), + std::make_tuple( "1 ", 1, false ), + std::make_tuple( " 1", 1, false ), + std::make_tuple( " 1 ", 1, false ), std::make_tuple( "-23", -23, false ), std::make_tuple( "4.5", 0, true ), std::make_tuple( "4.", 0, true ), std::make_tuple( "alpha", 0, true ), std::make_tuple( "1beta234", 0, true ), std::make_tuple( "1234gamma", 0, true ), - std::make_tuple( "1 ", 0, true ), std::make_tuple( "1 2", 0, true ))); @@ -374,12 +380,16 @@ TEST( testXmlWrapper, testGroupNamesFormats ) GroupNameTest( groupNameRegex, "testname01" ), GroupNameTest( groupNameRegex, "test_name" ), GroupNameTest( groupNameRegex, "test-name" ), - GroupNameTest( groupNameRegex, "test.name" ), + GroupNameTest( groupNameRegex, " testname " ), + GroupNameTest( groupNameRegex, " \t testname \n " ), }; for( GroupNameTest const & input : workingInputs ) { EXPECT_NO_THROW( xmlWrapper::stringToInputVariable( groupName, input.m_valueToTest, input.m_regex ) ); - EXPECT_STREQ( input.m_valueToTest.c_str(), groupName.c_str() ); + std::string groupNameComp; + std::istringstream ss( input.m_valueToTest ); + ss >> groupNameComp >> std::ws; + EXPECT_STREQ( groupNameComp.c_str(), groupName.c_str() ); } } { @@ -391,8 +401,6 @@ TEST( testXmlWrapper, testGroupNamesFormats ) //white spaces GroupNameTest( groupNameRegex, "test name" ), GroupNameTest( groupNameRegex, "test\tname" ), - GroupNameTest( groupNameRegex, "testname " ), - GroupNameTest( groupNameRegex, " testname" ), //fordbiden characters GroupNameTest( groupNameRegex, "test/name" ), GroupNameTest( groupNameRegex, "test:name" ), @@ -407,6 +415,93 @@ TEST( testXmlWrapper, testGroupNamesFormats ) } } } +TEST( testXmlWrapper, testGroupNamesArrayFormats ) +{ + struct GroupNameTest + { + Regex const & m_regex; + string m_valueToTest; + GroupNameTest( Regex const & regex, string_view valueToTest ): + m_regex( regex ), m_valueToTest( valueToTest ) {} + }; + + Regex const & groupNameRefArrayRegex = rtTypes::getTypeRegex< string >( rtTypes::CustomTypes::groupNameRefArray ); + string groupName; + + { + stdVector< GroupNameTest > workingInputs = { + GroupNameTest( groupNameRefArrayRegex, "{}" ), + GroupNameTest( groupNameRefArrayRegex, " {} " ), + GroupNameTest( groupNameRefArrayRegex, " \t {} \n " ), + GroupNameTest( groupNameRefArrayRegex, "{groupName}" ), + GroupNameTest( groupNameRefArrayRegex, "{123name}" ), + GroupNameTest( groupNameRefArrayRegex, "{name123}" ), + GroupNameTest( groupNameRefArrayRegex, "{a-Z0-9./*[]-_,}" ), + GroupNameTest( groupNameRefArrayRegex, "{name.with-special_chars}" ), + GroupNameTest( groupNameRefArrayRegex, "{path/to/resource*}" ), + GroupNameTest( groupNameRefArrayRegex, "{[arrayElement]}" ), + GroupNameTest( groupNameRefArrayRegex, "{name1,name2,name3}" ), + }; + for( GroupNameTest const & input : workingInputs ) + { + EXPECT_NO_THROW( xmlWrapper::stringToInputVariable( groupName, input.m_valueToTest, input.m_regex ) ); + std::string groupNameComp; + std::istringstream ss( input.m_valueToTest ); + ss >> groupNameComp >> std::ws; + EXPECT_STREQ( groupNameComp.c_str(), groupName.c_str() ); + } + } + { + stdVector< GroupNameTest > erroneousInputs = { + GroupNameTest( groupNameRefArrayRegex, "" ), + GroupNameTest( groupNameRefArrayRegex, " " ), + GroupNameTest( groupNameRefArrayRegex, " \t " ), + GroupNameTest( groupNameRefArrayRegex, "{\t}" ), + GroupNameTest( groupNameRefArrayRegex, "{test:name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test;name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test\\name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test|name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test^name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test$name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test&name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test#name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test!name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test%name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test@name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test(name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test)name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test=name}" ), + GroupNameTest( groupNameRefArrayRegex, "{test+name}" ), + GroupNameTest( groupNameRefArrayRegex, "{testname}" ), + GroupNameTest( groupNameRefArrayRegex, "{test\tname}" ), + GroupNameTest( groupNameRefArrayRegex, "{test\nname}" ), + GroupNameTest( groupNameRefArrayRegex, "{test\rname}" ), + GroupNameTest( groupNameRefArrayRegex, "groupName" ), + GroupNameTest( groupNameRefArrayRegex, "{groupName" ), + GroupNameTest( groupNameRefArrayRegex, "groupName}" ), + GroupNameTest( groupNameRefArrayRegex, "{groupName}} " ), + GroupNameTest( groupNameRefArrayRegex, "{}groupName" ), + GroupNameTest( groupNameRefArrayRegex, "groupName{}" ), + GroupNameTest( groupNameRefArrayRegex, "{hello, \t\n\r ,world}" ), + GroupNameTest( groupNameRefArrayRegex, "test{groupName}" ), + GroupNameTest( groupNameRefArrayRegex, "{groupName}test" ), + GroupNameTest( groupNameRefArrayRegex, "{groupName} test" ), + GroupNameTest( groupNameRefArrayRegex, "{element with space, another}" ), + GroupNameTest( groupNameRefArrayRegex, "{element, element with space, 123.456, a-b}" ), + GroupNameTest( groupNameRefArrayRegex, "{ space at ends } " ), + GroupNameTest( groupNameRefArrayRegex, "{valuewith,,commas }" ), + GroupNameTest( groupNameRefArrayRegex, "{ value with , commas }" ), + GroupNameTest( groupNameRefArrayRegex, "{{groupname}}" ), + }; + for( GroupNameTest const & input : erroneousInputs ) + { + EXPECT_THROW( xmlWrapper::stringToInputVariable( groupName, input.m_valueToTest, input.m_regex ), + InputError ) << "Parsing input '"<< input.m_valueToTest + << "' with regex '" << input.m_regex.m_regexStr << "' didn't throw an InputError as expected."; + } + } +} int main( int argc, char * argv[] ) diff --git a/src/coreComponents/dataRepository/xmlWrapper.hpp b/src/coreComponents/dataRepository/xmlWrapper.hpp index 011836ad01f..5955d95e7f5 100644 --- a/src/coreComponents/dataRepository/xmlWrapper.hpp +++ b/src/coreComponents/dataRepository/xmlWrapper.hpp @@ -351,8 +351,8 @@ std::enable_if_t< traits::CanStreamInto< std::istringstream, T > > stringToInputVariable( T & target, string const & value, Regex const & regex ) { validateString( value, regex ); - - std::istringstream ss( value ); + string_view stringTrimed = stringutilities::trimSpaces( value ); + std::istringstream ss( (string( stringTrimed )) ); ss >> target; GEOS_THROW_IF( ss.fail() || !ss.eof(), "Error detected while parsing string \"" << value << diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd index 524c0e52517..e32bfc23232 100644 --- a/src/coreComponents/schema/schema.xsd +++ b/src/coreComponents/schema/schema.xsd @@ -5,167 +5,167 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -3653,8 +3653,9 @@ Information output from lower logLevels is added with the desired log level +Frequency of pressure update is set in SinglePhase/CompositionalMultiphaseStatistics definition. +Setting cycleFrequency='1' will update the pressure every timestep, note that is a lagged property in constraint propertiesNote the event associated with the statists task must be entered before the solver event. +--> diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other index 35676a136fc..2e1e8c638b3 100644 --- a/src/coreComponents/schema/schema.xsd.other +++ b/src/coreComponents/schema/schema.xsd.other @@ -5,167 +5,167 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +