| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| using System.IO; |
| using org.apache.plc4net.tools.codegen; |
| using Xunit; |
| |
| namespace org.apache.plc4net.test.codegen |
| { |
| /// <summary> |
| /// Verifies that the pure-.NET mspec parser can parse the Modbus protocol |
| /// description, which is the simplest of the 24 protocol descriptions and |
| /// therefore the first target for the generator pipeline. |
| /// </summary> |
| public class MspecParserTests |
| { |
| private static string? GetModbusMspecPath() |
| { |
| // The mspec file lives in the repo root under protocols/modbus/... |
| // FindRepoRoot walks up from the test output directory; null means |
| // the tests are not running inside a checkout. |
| var repoRoot = RepoPaths.FindRepoRoot(); |
| if (repoRoot == null) return null; |
| return Path.Combine(repoRoot, |
| "protocols", "modbus", "src", "main", "resources", |
| "protocols", "modbus", "modbus.mspec"); |
| } |
| |
| [Fact] |
| public void Modbus_mspec_parses_without_errors() |
| { |
| var path = GetModbusMspecPath(); |
| if (path == null) |
| { |
| // Fail loud rather than passing vacuously outside the repo layout. |
| Assert.Fail("repo root not found; real-protocol coverage would be vacuous"); |
| } |
| |
| // Deliberately no File.Exists guard here: inside a checkout the |
| // file must exist, and a missing one is a real error worth failing |
| // on, not a reason to pass vacuously. |
| var tree = MspecReader.ReadFile(path); |
| |
| Assert.NotNull(tree); |
| } |
| |
| [Fact] |
| public void A_minimal_mspec_parses() |
| { |
| var mspec = @" |
| [type Byte |
| [simple uint 8 value] |
| ] |
| "; |
| var tree = MspecReader.Read(mspec); |
| Assert.NotNull(tree); |
| } |
| |
| [Fact] |
| public void Malformed_mspec_throws() |
| { |
| var ex = Assert.Throws<MspecParseException>( |
| () => MspecReader.Read("[type Broken <<<")); |
| |
| Assert.Contains("Failed to parse", ex.Message); |
| } |
| |
| [Fact] |
| public void A_lexer_error_is_reported_by_strict_parsing() |
| { |
| var ex = Assert.Throws<MspecParseException>( |
| () => MspecReader.Read("[type Packet [simple uint 8 value] @]")); |
| |
| Assert.Contains("token recognition error", ex.Message); |
| } |
| } |
| } |