/*
Copyright 2021 Equinor.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see .
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include
#include
#include
#include
#define BOOST_TEST_MODULE KeywordValidatorTest
#include
using namespace Opm;
using namespace Opm::KeywordValidation;
const UnsupportedKeywords test_unsupported_keywords = {
{"ECHO", {false, "This is not a critical error"}},
{"NOECHO", {true, std::nullopt}},
};
const PartiallySupportedKeywords test_string_items = {
{
"PINCH",
{
{2, {false, allow_values {"GAP", "BAR"}, std::nullopt}}, // GAP
{4, {true, allow_values {"TOPBOT"}, "This is a critical error"}}, // PINCHOUT_OPTION
},
},
{
"EQLOPTS",
{
{1, {false, allow_values {}, std::nullopt}},
{3, {false, allow_values {"THPRESS"}, std::nullopt}},
},
},
};
const PartiallySupportedKeywords test_int_items = {
{
"ENDSCALE",
{
{3, {false, allow_values {1}, std::nullopt}}, // NTENDP
{4, {true, allow_values {20, 30, 40}, std::nullopt}}, // NSENDP
},
},
{
"COMPDAT",
{
{2, {false, allow_values {1}, std::nullopt}}, // I
{3, {false, allow_values {1}, std::nullopt}}, // J
},
},
};
const PartiallySupportedKeywords test_double_items = {
{
"EHYSTR",
{
{1, {false, [](double x) { return x > 0; }, std::nullopt}},
{3, {false, allow_values {1.0, 2.0}, std::nullopt}},
},
},
};
BOOST_AUTO_TEST_CASE(non_critical_keyword)
{
const auto keywords_string = std::string {R"(
ECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(!errors[0].critical);
BOOST_CHECK(!errors[0].item_number);
BOOST_CHECK(!errors[0].item_value);
BOOST_CHECK(*(errors[0].user_message) == "This is not a critical error");
}
BOOST_AUTO_TEST_CASE(critical_keyword)
{
const auto keywords_string = std::string {R"(
NOECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["NOECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors[0].critical);
BOOST_CHECK(!errors[0].item_number);
BOOST_CHECK(!errors[0].item_value);
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(non_critical_keyword_item_string)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 FOO 1* 1* /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["PINCH"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(!errors[0].critical);
BOOST_CHECK(errors[0].item_number == 2);
BOOST_CHECK(errors[0].item_value == "FOO");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(critical_keyword_item_string)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 GAP 1* FOO /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["PINCH"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors[0].critical);
BOOST_CHECK(errors[0].item_number == 4);
BOOST_CHECK(errors[0].item_value == "FOO");
BOOST_CHECK(*(errors[0].user_message) == "This is a critical error");
}
BOOST_AUTO_TEST_CASE(non_critical_keyword_item_int)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 0 20 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(!errors[0].critical);
BOOST_CHECK(errors[0].item_number == 3);
BOOST_CHECK(errors[0].item_value == "0");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(critical_keyword_item_int)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 1 0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors[0].critical);
BOOST_CHECK(errors[0].item_number == 4);
BOOST_CHECK(errors[0].item_value == "0");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(non_critical_keyword_item_double_ok)
{
const auto keywords_string = std::string {R"(
EHYSTR
1.0 0 1.0/
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EHYSTR"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors.size() == 0);
}
BOOST_AUTO_TEST_CASE(non_critical_keyword_item_double)
{
const auto keywords_string = std::string {R"(
EHYSTR
1.0 0 10.0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EHYSTR"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(!errors[0].critical);
BOOST_CHECK(errors[0].item_number == 3);
BOOST_CHECK(errors[0].item_value == "10.000000");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(non_critical_keyword_item_double_lambda)
{
const auto keywords_string = std::string {R"(
EHYSTR
-1.0 0 1.0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EHYSTR"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(!errors[0].critical);
BOOST_CHECK(errors[0].item_number == 1);
BOOST_CHECK(errors[0].item_value == "-1.000000");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(two_keyword_errors)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 GAP 1* FOO /
ENDSCALE
NODIR REVERS 1 0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword1 = deck["PINCH"].back();
const auto& test_keyword2 = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword1, errors);
validator.validateDeckKeyword(test_keyword2, errors);
BOOST_CHECK(errors[0].critical);
BOOST_CHECK(errors[0].item_number == 4);
BOOST_CHECK(errors[0].item_value == "FOO");
BOOST_CHECK(*(errors[0].user_message) == "This is a critical error");
BOOST_CHECK(errors[1].critical);
BOOST_CHECK(errors[1].item_number == 4);
BOOST_CHECK(errors[1].item_value == "0");
BOOST_CHECK(!errors[1].user_message);
}
BOOST_AUTO_TEST_CASE(report_not_critical)
{
const auto keywords_string = std::string {R"(
ECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" ECHO: keyword not supported\n"
" In file: , line 2\n"
" This is not a critical error");
}
BOOST_AUTO_TEST_CASE(report_critical_missing)
{
const auto keywords_string = std::string {R"(
ECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report.empty());
}
BOOST_AUTO_TEST_CASE(report_critical)
{
const auto keywords_string = std::string {R"(
NOECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["NOECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" NOECHO: keyword not supported\n"
" In file: , line 2");
}
BOOST_AUTO_TEST_CASE(report_not_critical_missing)
{
const auto keywords_string = std::string {R"(
NOECHO
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["NOECHO"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report.empty());
}
BOOST_AUTO_TEST_CASE(error_report_non_critical_keyword_item_string)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 FOO 1* 1* /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["PINCH"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" PINCH: invalid value 'FOO' for item 2\n"
" In file: , line 2");
}
BOOST_AUTO_TEST_CASE(error_report_non_critical_keyword_item_string_two_records)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 GAP 1* 1* /
COMPDAT
C-4H 0 1 1 1 OPEN 1* 4.088536E+1 0.21600 1* 0.00000 1* 'Z' /
C-4H 1 0 2 2 OPEN 1* 7.072475E+1 0.21600 1* 0.00000 1* 'Z' /
/
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["COMPDAT"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" COMPDAT: invalid value '0' in record 1 for item 2\n"
" In file: , line 4\n\n"
" COMPDAT: invalid value '0' in record 2 for item 3\n"
" In file: , line 4");
}
BOOST_AUTO_TEST_CASE(error_report_non_critical_keyword_item_string_missing)
{
const auto keywords_string = std::string {R"(
PINCH
0.41 FOO 1* 1* /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["PINCH"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report.empty());
}
BOOST_AUTO_TEST_CASE(error_report_non_critical_keyword_item_int)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 0 20 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" ENDSCALE: invalid value '0' for item 3\n"
" In file: , line 2");
}
BOOST_AUTO_TEST_CASE(error_report_non_critical_keyword_item_int_missing)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 0 20 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report.empty());
}
BOOST_AUTO_TEST_CASE(error_report_critical_keyword_item_int)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 1 0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" ENDSCALE: invalid value '0' for item 4\n"
" In file: , line 2");
}
BOOST_AUTO_TEST_CASE(error_report_critical_keyword_item_int_missing)
{
const auto keywords_string = std::string {R"(
ENDSCALE
NODIR REVERS 1 0 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report.empty());
}
BOOST_AUTO_TEST_CASE(error_report_all_not_critical)
{
const auto keywords_string = std::string {R"(
ECHO
NOECHO
PINCH
0.41 GAP 1* FOO /
ENDSCALE
NODIR REVERS 0 20 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword1 = deck["ECHO"].back();
const auto& test_keyword2 = deck["NOECHO"].back();
const auto& test_keyword3 = deck["PINCH"].back();
const auto& test_keyword4 = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword1, errors);
validator.validateDeckKeyword(test_keyword2, errors);
validator.validateDeckKeyword(test_keyword3, errors);
validator.validateDeckKeyword(test_keyword4, errors);
const auto report = get_error_report(errors, true, false);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" ECHO: keyword not supported\n"
" In file: , line 2\n"
" This is not a critical error\n\n"
" ENDSCALE: invalid value '0' for item 3\n"
" In file: , line 6");
}
BOOST_AUTO_TEST_CASE(error_report_not_critical)
{
const auto keywords_string = std::string {R"(
ECHO
NOECHO
PINCH
0.41 GAP 1* FOO /
ENDSCALE
NODIR REVERS 0 20 /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword1 = deck["ECHO"].back();
const auto& test_keyword2 = deck["NOECHO"].back();
const auto& test_keyword3 = deck["PINCH"].back();
const auto& test_keyword4 = deck["ENDSCALE"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword1, errors);
validator.validateDeckKeyword(test_keyword2, errors);
validator.validateDeckKeyword(test_keyword3, errors);
validator.validateDeckKeyword(test_keyword4, errors);
const auto report = get_error_report(errors, false, true);
BOOST_CHECK(report
== "Unsupported keywords or keyword items:\n\n"
" NOECHO: keyword not supported\n"
" In file: , line 3\n\n"
" PINCH: invalid value 'FOO' for item 4\n"
" In file: , line 4\n"
" This is a critical error");
}
BOOST_AUTO_TEST_CASE(keyword_without_default)
{
const auto keywords_string = std::string {R"(
EQLOPTS
1* /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EQLOPTS"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors.size() == 0);
}
BOOST_AUTO_TEST_CASE(keyword_without_default_with_wrong_value)
{
const auto keywords_string = std::string {R"(
EQLOPTS
FOO /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EQLOPTS"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors.size() == 1);
BOOST_CHECK(errors[0].item_number == 1);
BOOST_CHECK(errors[0].item_value == "FOO");
BOOST_CHECK(!errors[0].user_message);
}
BOOST_AUTO_TEST_CASE(keyword_without_default_with_correct_value)
{
const auto keywords_string = std::string {R"(
EQLOPTS
1* 1* THPRESS /
)"};
const auto deck = Parser {}.parseString(keywords_string);
const auto& test_keyword = deck["EQLOPTS"].back();
KeywordValidator validator(test_unsupported_keywords, test_string_items, test_int_items, test_double_items, {});
std::vector errors;
validator.validateDeckKeyword(test_keyword, errors);
BOOST_CHECK(errors.size() == 0);
}