Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions docs/developers_guide/input_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ item.domain.set_rule("value>0 and value<=1");
item.domain.add_requirement("noncolin==true or lspinorb==true", "nspin==4");
```

These are independent examples of declarations. Scalar readers register their
actual numeric/Boolean type automatically. The existing `sync_*` registrations
These are independent examples of declarations. Ordinary scalar readers register
their numeric/Boolean/string type automatically. A supplied ordinary string
parameter must have exactly one token, so a bare `stru_file` is rejected with
the expected type and manual link before its reader accesses the value. This
also rejects extra tokens that would otherwise be silently discarded.
The existing `sync_*` registrations
supply typed, read-only value access, including nested MD fields and vectors.
The checker does not infer token cardinality from a prose documentation type,
or format final values and parse them back. Custom input grammars remain in
Expand Down Expand Up @@ -50,7 +54,7 @@ explicit supplied values are still checked.

## Documentation and defaults

The normal numeric/Boolean reader registrations enforce scalar type contracts
The normal numeric/Boolean/string reader registrations enforce scalar type contracts
automatically. Explicit choice/range/requirement declarations cover system,
electronic, relaxation, MD, vdW, output, DeePKS, DFPT and TDDFT inputs, including
`scf_thr_type`, `symmetry`, `mem_saver` and the spin dependency.
Expand Down
1 change: 1 addition & 0 deletions source/source_io/module_parameter/read_input_tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@

#define read_sync_string(PARAMETER) \
{ \
item.domain.scalar(); \
Comment thread
Stardust0831 marked this conversation as resolved.
item.read_value = [](const Input_Item& item, Parameter& para) { para.PARAMETER = strvalue; }; \
sync_string(PARAMETER); \
}
Expand Down
46 changes: 46 additions & 0 deletions source/source_io/test_serial/test_read_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,52 @@ TEST_F(InputDomainReaderTest, PreservesLegacyEmptyValues)
EXPECT_TRUE(input.inp.out_pchg.empty());
}

TEST_F(InputDomainReaderTest, RejectsMissingOrdinaryStringValues)
{
for (const std::string label : {"stru_file", "kpoint_file", "suffix", "dft_functional"})
{
for (const std::string ending : {"", "\n", " # missing value\n", " ! missing value\n"})
{
const std::string values = label + ending;
const std::string output = reject_input(values);
const std::string diagnostic = "Invalid INPUT parameter '" + label + "': supplied ''";
const std::string manual = ModuleIO::input_manual_link(label);
EXPECT_NE(output.find(diagnostic), std::string::npos);
EXPECT_NE(output.find("Expected one String."), std::string::npos);
EXPECT_NE(output.find(manual), std::string::npos);
EXPECT_NE(output.find(filename), std::string::npos);
}
}
}

TEST_F(InputDomainReaderTest, RejectsExtraOrdinaryStringValues)
{
const std::string output = reject_input("stru_file STRU extra\n");
EXPECT_NE(output.find("supplied 'STRU extra'"), std::string::npos);
EXPECT_NE(output.find("Expected one String."), std::string::npos);
EXPECT_NE(output.find("input-main.html#stru-file"), std::string::npos);
}

TEST_F(InputDomainReaderTest, KeepsExplicitStringPathsAndOmittedDefaults)
{
write_input("stru_file /tmp/structure\nkpoint_file //server/KPT # custom path\n");
ModuleIO::ReadInput reader(0);
reader.check_ntype_flag = false;
Parameter input;
reader.read_parameters(input, filename);
EXPECT_EQ(input.inp.stru_file, "/tmp/structure");
EXPECT_EQ(input.inp.kpoint_file, "//server/KPT");
EXPECT_EQ(input.inp.suffix, "ABACUS");

write_input("");
ModuleIO::ReadInput defaults_reader(0);
defaults_reader.check_ntype_flag = false;
Parameter defaults;
defaults_reader.read_parameters(defaults, filename);
EXPECT_EQ(defaults.inp.stru_file, "STRU");
EXPECT_EQ(defaults.inp.kpoint_file, "KPT");
}

TEST_F(InputDomainReaderTest, KeepsTrailingCommentsAndAbsolutePaths)
{
write_input("scf_thr 1e-7 // about iteration\n"
Expand Down
Loading