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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
74 changes: 18 additions & 56 deletions dev_scripts/codegen/meta_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Downloaded from: https://raw.githubusercontent.com/aas-core-works/aas-core-meta/899add10ff71eca9dac421c3a171bb909c68cb2c/aas_core_meta/v3_1.py
# Downloaded from: https://raw.githubusercontent.com/aas-core-works/aas-core-meta/5a498be3a3b56f34af9a90b368cae10ca04e7ae4/aas_core_meta/v3_1.py
"""
--- WORK IN PROGRESS ---
Provide an implementation of the Asset Administration Shell (AAS) V3.1.
Expand Down Expand Up @@ -280,52 +280,6 @@ def matches_RFC_2396(text: str) -> bool:
return match(uri_reference, text) is not None


# noinspection SpellCheckingInspection
@verification
def matches_RFC_8089_path(text: str) -> bool:
"""
Check that :paramref:`text` is a path conforming to the pattern of RFC 8089.

The definition has been taken from:
https://datatracker.ietf.org/doc/html/rfc8089

:param text: Text to be checked
:returns: True if the :paramref:`text` conforms to the pattern

"""
h16 = "[0-9A-Fa-f]{1,4}"
dec_octet = "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
ipv4address = f"{dec_octet}\\.{dec_octet}\\.{dec_octet}\\.{dec_octet}"
ls32 = f"({h16}:{h16}|{ipv4address})"
ipv6address = (
f"(({h16}:){{6}}{ls32}|::({h16}:){{5}}{ls32}|({h16})?::({h16}:){{4}}"
f"{ls32}|(({h16}:)?{h16})?::({h16}:){{3}}{ls32}|(({h16}:){{,2}}{h16})?::"
f"({h16}:){{2}}{ls32}|(({h16}:){{,3}}{h16})?::{h16}:{ls32}|(({h16}:){{,4}}"
f"{h16})?::{ls32}|(({h16}:){{,5}}{h16})?::{h16}|(({h16}:){{,6}}{h16})?"
"::)"
)
unreserved = "[a-zA-Z0-9\\-._~]"
sub_delims = "[!$&'()*+,;=]"
ipvfuture = f"[vV][0-9A-Fa-f]+\\.({unreserved}|{sub_delims}|:)+"
ip_literal = f"\\[({ipv6address}|{ipvfuture})\\]"
pct_encoded = "%[0-9A-Fa-f][0-9A-Fa-f]"
reg_name = f"({unreserved}|{pct_encoded}|{sub_delims})*"
host = f"({ip_literal}|{ipv4address}|{reg_name})"
file_auth = f"(localhost|{host})"
pchar = f"({unreserved}|{pct_encoded}|{sub_delims}|[:@])"
segment_nz = f"({pchar})+"
segment = f"({pchar})*"
path_absolute = f"/({segment_nz}(/{segment})*)?"
auth_path = f"({file_auth})?{path_absolute}"
local_path = f"{path_absolute}"
file_hier_part = f"(//{auth_path}|{local_path})"
file_scheme = "file"
file_uri = f"{file_scheme}:{file_hier_part}"

pattern = f"^{file_uri}$"
return match(pattern, text) is not None


# noinspection SpellCheckingInspection
@verification
def matches_BCP_47(text: str) -> bool:
Expand Down Expand Up @@ -2279,8 +2233,9 @@ class Asset_information(DBC):

asset_kind: "Asset_kind"
"""
Denotes whether the Asset is of kind :attr:`Asset_kind.Type` or
:attr:`Asset_kind.Instance`.
Denotes whether the Asset is of kind :attr:`Asset_kind.Type`,
:attr:`Asset_kind.Instance`, :attr:`Asset_kind.Role`, or
:attr:`Asset_kind.Not_applicable`.
"""

global_asset_ID: Optional["Identifier"]
Expand All @@ -2305,13 +2260,13 @@ class Asset_information(DBC):

asset_type: Optional["Identifier"]
"""
In case :attr:`asset_kind` is applicable the :attr:`asset_type` is the asset ID
of the type asset of the asset under consideration
as identified by :attr:`global_asset_ID`.
In case :attr:`asset_kind` is :attr:`Asset_kind.Not_applicable` the
:attr:`asset_type` is the asset ID of the type asset of the asset under
consideration as identified by :attr:`global_asset_ID`.

.. note::

In case :attr:`asset_kind` is "Instance" than the :attr:`asset_type` denotes
In case :attr:`asset_kind` is "Instance" then the :attr:`asset_type` denotes
which "Type" the asset is of. But it is also possible
to have an :attr:`asset_type` of an asset of kind "Type".

Expand Down Expand Up @@ -2370,7 +2325,8 @@ def __init__(

class Asset_kind(Enum):
"""
Enumeration for denoting whether an asset is a type asset or an instance asset.
Enumeration for denoting whether an asset is a type asset or an instance
asset or is a role or whether this kind of classification is not applicable.
"""

Type = "Type"
Expand Down Expand Up @@ -2694,6 +2650,12 @@ class AAS_submodel_elements(Enum):


# fmt: off
@invariant(
lambda self:
not (self.value is not None)
or ID_shorts_are_unique(self.value),
"ID-shorts of the value must be unique."
)
@invariant(
lambda self:
not (
Expand Down Expand Up @@ -3920,7 +3882,7 @@ def __init__(
self.inoutput_variables
),
"Constraint AASd-134: For an Operation the ID-short of all values of "
"input, output and in/output variables."
"input, output and in/output variables shall be unique."
)
# fmt: on
class Operation(Submodel_element):
Expand Down Expand Up @@ -5714,4 +5676,4 @@ def __init__(
self.value = value
self.level_type = level_type

# Downloaded from: https://raw.githubusercontent.com/aas-core-works/aas-core-meta/899add10ff71eca9dac421c3a171bb909c68cb2c/aas_core_meta/v3_1.py
# Downloaded from: https://raw.githubusercontent.com/aas-core-works/aas-core-meta/5a498be3a3b56f34af9a90b368cae10ca04e7ae4/aas_core_meta/v3_1.py

This file was deleted.

129 changes: 129 additions & 0 deletions src/AasCore.Aas3_1.Tests/Common.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using Aas = AasCore.Aas3_1; // renamed

using System.Collections.Generic; // can't alias
using System.Linq; // can't alias
using NUnit.Framework; // can't alias

namespace AasCore.Aas3_1.Tests
{
/// <summary>
/// Provide common functionality to be re-used across different tests
/// such as reading of environment variables.
/// </summary>
public static class Common
{
public static readonly string RecordModeEnvironmentVariableName = (
"AAS_CORE_AAS3_1_TESTS_RECORD_MODE"
);

// NOTE (mristin, 2023-03-16):
// It is tedious to record manually all the expected error messages. Therefore we include this variable
// to steer the automatic recording. We intentionally inter-twine the recording code with the test code
// to keep them close to each other so that they are easier to maintain.
public static readonly bool RecordMode = (
System.Environment.GetEnvironmentVariable(RecordModeEnvironmentVariableName)?.ToLower()
== "true"
|| System
.Environment.GetEnvironmentVariable(RecordModeEnvironmentVariableName)
?.ToLower() == "on"
|| System
.Environment.GetEnvironmentVariable(RecordModeEnvironmentVariableName)
?.ToLower() == "1"
|| System
.Environment.GetEnvironmentVariable(RecordModeEnvironmentVariableName)
?.ToLower() == "yes"
);

public static readonly string TestDataDir = (
System.Environment.GetEnvironmentVariable("AAS_CORE_AAS3_1_TESTS_TEST_DATA_DIR")
?? throw new System.InvalidOperationException(
"The path to the test data directory is missing in the environment: "
+ "AAS_CORE_AAS3_1_TESTS_TEST_DATA_DIR"
)
);

/// <summary>
/// Find the first instance of <typeparamref name="T"/> in the <paramref name="container" />,
/// including the <paramref name="container" /> itself.
/// </summary>
public static T MustFind<T>(Aas.IClass container)
where T : Aas.IClass
{
var instance = (
(container is T)
? container
: container.Descend().First(something => something is T)
?? throw new System.InvalidOperationException(
$"No instance of {nameof(T)} could be found"
)
);

return (T)instance;
}

public static void AssertNoVerificationErrors(List<Aas.Reporting.Error> errors, string path)
{
if (errors.Count > 0)
{
var builder = new System.Text.StringBuilder();
builder.Append(
$"Expected no errors when verifying the instance de-serialized from {path}, "
+ $"but got {errors.Count} error(s):\n"
);
for (var i = 0; i < errors.Count; i++)
{
builder.Append(
$"Error {i + 1}:\n"
+ $"{Reporting.GenerateJsonPath(errors[i].PathSegments)}: {errors[i].Cause}\n"
);
}

Assert.Fail(builder.ToString());
}
}

public static void AssertEqualsExpectedOrRerecordVerificationErrors(
List<Aas.Reporting.Error> errors,
string path
)
{
if (errors.Count == 0)
{
Assert.Fail(
$"Expected at least one verification error when verifying {path}, but got none"
);
}

string got = string.Join(
";\n",
errors.Select(error =>
$"{Reporting.GenerateJsonPath(error.PathSegments)}: {error.Cause}"
)
);

string errorsPath = path + ".errors";
if (RecordMode)
{
System.IO.File.WriteAllText(errorsPath, got);
}
else
{
if (!System.IO.File.Exists(errorsPath))
{
throw new System.IO.FileNotFoundException(
"The file with the recorded errors does not "
+ $"exist: {errorsPath}; maybe you want to set the environment "
+ $"variable {Aas.Tests.Common.RecordModeEnvironmentVariableName}?"
);
}

string expected = System.IO.File.ReadAllText(errorsPath);
Assert.AreEqual(
expected.Replace("\r\n", "\n"),
got.Replace("\r\n", "\n"),
$"The expected verification errors do not match the actual ones for the file {path}"
);
}
}
}
}
Loading