fix: enforce phase1 parser subset

This commit is contained in:
NINI
2026-05-04 13:03:20 +09:00
parent 99445d43bb
commit c0f668754d
6 changed files with 329 additions and 23 deletions
+165
View File
@@ -105,6 +105,25 @@ fesa::Domain parsedPhase1Domain() {
return parsed.domain;
}
const fesa::Diagnostic* findDiagnostic(const std::vector<fesa::Diagnostic>& diagnostics, const std::string& code) {
for (const auto& diagnostic : diagnostics) {
if (diagnostic.code == code) {
return &diagnostic;
}
}
return nullptr;
}
std::size_t diagnosticCount(const std::vector<fesa::Diagnostic>& diagnostics, const std::string& code) {
std::size_t count = 0;
for (const auto& diagnostic : diagnostics) {
if (diagnostic.code == code) {
++count;
}
}
return count;
}
} // namespace
FESA_TEST(core_types_and_dof_mapping_are_stable) {
@@ -144,24 +163,170 @@ FESA_TEST(parser_accepts_phase1_subset) {
FESA_CHECK(parsed.domain.loads.size() == 2);
}
FESA_TEST(parser_accepts_repeated_and_generated_sets) {
const std::string text = R"inp(
*Node
1, 0, 0, 0
2, 1, 0, 0
3, 1, 1, 0
4, 0, 1, 0
*Element, type=S4, elset=EALL
1, 1, 2, 3, 4
*Nset, nset=FIXED
1, 2, 2
3
*Nset, nset=FIXED, generate
3, 4, 1
*Nset, nset=LOADS, generate
2, 4, 2
*Elset, elset=EALL
1, 1
*Elset, elset=CHECK, generate
1, 5, 2
*Material, name=MAT
*Elastic
2.0D5, 0.25
*Shell Section, elset=EALL, material=MAT
0.2
*Boundary
FIXED, 1, 6
*Cload
LOADS, 3, -2.5
*Step, name=Step-A, nlgeom=NO
*Static
*End Step
)inp";
fesa::AbaqusInputParser parser;
auto parsed = parser.parseString(text);
FESA_CHECK(parsed.ok());
FESA_CHECK(parsed.domain.node_sets.at("fixed").node_ids == std::vector<fesa::GlobalId>({1, 2, 3, 4}));
FESA_CHECK(parsed.domain.node_sets.at("loads").node_ids == std::vector<fesa::GlobalId>({2, 4}));
FESA_CHECK(parsed.domain.element_sets.at("eall").element_ids == std::vector<fesa::GlobalId>({1}));
FESA_CHECK(parsed.domain.element_sets.at("check").element_ids == std::vector<fesa::GlobalId>({1, 3, 5}));
FESA_CHECK(parsed.domain.materials.at("mat").elastic_modulus == 2.0e5);
FESA_CHECK(parsed.domain.steps.front().name == "Step-A");
}
FESA_TEST(parser_accepts_keyword_line_continuation) {
const std::string text = R"inp(
*Node
1, 0, 0, 0
2, 1, 0, 0
3, 1, 1, 0
4, 0, 1, 0
*Element,
type=S4, elset=EALL
1, 1, 2, 3, 4
*Nset,
nset=FIXED, generate
1, 4, 3
*Elset,
elset=EALL
1
*Material,
name=MAT
*Elastic
2.0e5, 0.25
*Shell Section,
elset=EALL, material=MAT
0.2
*Boundary
FIXED, 1, 6
*Cload
2, 3, -1.0
*Step,
name=Step-1
*Static
*End Step
)inp";
fesa::AbaqusInputParser parser;
auto parsed = parser.parseString(text);
FESA_CHECK(parsed.ok());
FESA_CHECK(parsed.domain.elements.at(1).source_elset == "EALL");
FESA_CHECK(parsed.domain.node_sets.at("fixed").node_ids == std::vector<fesa::GlobalId>({1, 4}));
FESA_CHECK(parsed.domain.materials.count("mat") == 1);
FESA_CHECK(parsed.domain.shell_sections.front().material == "MAT");
}
FESA_TEST(parser_rejects_unsupported_features) {
const std::string text = R"inp(
*Part, name=P1
*Assembly, name=A1
*Instance, name=I1, part=P1
*Include, input=other.inp
*Node
1, 0, 0, 0
*Element, type=S4R
1, 1, 2, 3, 4
*Density
7850
*Step, nlgeom=YES
*End Step
)inp";
fesa::AbaqusInputParser parser;
auto parsed = parser.parseString(text);
FESA_CHECK(!parsed.ok());
FESA_CHECK(diagnosticCount(parsed.diagnostics, "FESA-PARSE-UNSUPPORTED-KEYWORD") >= 4);
FESA_CHECK(fesa::containsDiagnostic(parsed.diagnostics, "FESA-PARSE-UNSUPPORTED-KEYWORD"));
FESA_CHECK(fesa::containsDiagnostic(parsed.diagnostics, "FESA-PARSE-UNSUPPORTED-ELEMENT"));
FESA_CHECK(fesa::containsDiagnostic(parsed.diagnostics, "FESA-PARSE-UNSUPPORTED-NLGEOM"));
}
FESA_TEST(parser_rejects_unsupported_keyword_parameters_and_modes) {
const std::string text = R"inp(
*Node, input=nodes.csv
1, 0, 0, 0
2, 1, 0, 0
3, 1, 1, 0
4, 0, 1, 0
*Element, type=S4, elset=EALL, orientation=OR1
1, 1, 2, 3, 4
*Nset, nset=FIXED, unsorted
1, 4
*Material, name=MAT, description=bad
*Elastic, type=ENGINEERING CONSTANTS
2.0e5, 0.25
*Shell Section, elset=EALL, material=MAT, offset=SPOS
0.2, 5
*Boundary, op=NEW
FIXED, 1, 6
*Cload, amplitude=A1
2, 3, -1.0
*Step, name=Step-1, inc=100
*Static, stabilize
*End Step
)inp";
fesa::AbaqusInputParser parser;
auto parsed = parser.parseString(text, "unsupported_modes.inp");
FESA_CHECK(!parsed.ok());
FESA_CHECK(diagnosticCount(parsed.diagnostics, "FESA-PARSE-UNSUPPORTED-PARAMETER") >= 8);
FESA_CHECK(fesa::containsDiagnostic(parsed.diagnostics, "FESA-PARSE-SHELL-SECTION-UNSUPPORTED"));
}
FESA_TEST(parser_diagnostics_include_file_line_and_keyword) {
const std::string text = R"inp(
*Node
1, bad, 0, 0
*Boundary
FIXED, 7, 7
)inp";
fesa::AbaqusInputParser parser;
auto parsed = parser.parseString(text, "malformed.inp");
FESA_CHECK(!parsed.ok());
const fesa::Diagnostic* node = findDiagnostic(parsed.diagnostics, "FESA-PARSE-NODE-NUMERIC");
FESA_CHECK(node != nullptr);
FESA_CHECK(node->source.file == "malformed.inp");
FESA_CHECK(node->source.line == 3);
FESA_CHECK(node->source.keyword == "node");
const fesa::Diagnostic* boundary = findDiagnostic(parsed.diagnostics, "FESA-PARSE-BOUNDARY-DOF");
FESA_CHECK(boundary != nullptr);
FESA_CHECK(boundary->source.file == "malformed.inp");
FESA_CHECK(boundary->source.line == 5);
FESA_CHECK(boundary->source.keyword == "boundary");
}
FESA_TEST(quad01_reference_input_remains_unsupported) {
fesa::AbaqusInputParser parser;
auto parsed = parser.parseFile(sourceRoot() + "/references/quad_01.inp");