Skip to main content

runmat_runtime/testing/
class_registry.rs

1use runmat_types::MemberAccess;
2use std::collections::HashMap;
3
4use crate::class_registry::{RuntimeClass, RuntimeMethod, RuntimeProperty};
5use runmat_value::Value;
6
7use super::objects::{
8    FUNCTION_TEST_CASE_CLASS, TEST_CASE_CLASS, TEST_RESULT_CLASS, TEST_SUITE_CLASS,
9};
10
11static REGISTERED: crate::class_registry::ClassRegistration =
12    crate::class_registry::ClassRegistration::new(TEST_CASE_CLASS);
13
14pub fn ensure_testing_classes() {
15    REGISTERED.ensure(|| {
16        register_test_case();
17        register_plain_class(
18            TEST_SUITE_CLASS,
19            None,
20            &["Name", "ProcedureName", "TestFile", "Tags"],
21        );
22        register_plain_class(
23            TEST_RESULT_CLASS,
24            None,
25            &[
26                "Name",
27                "TestFile",
28                "Passed",
29                "Failed",
30                "Incomplete",
31                "Duration",
32                "Details",
33                "Flaky",
34            ],
35        );
36        register_class_with_methods(
37            "matlab.unittest.TestRunner",
38            Some("handle"),
39            &["Plugins"],
40            &["addPlugin", "run"],
41        );
42        register_plain_class(
43            "matlab.unittest.fixtures.Fixture",
44            Some("handle"),
45            &["Name"],
46        );
47        register_plain_class(
48            "matlab.unittest.fixtures.TemporaryFolderFixture",
49            Some("matlab.unittest.fixtures.Fixture"),
50            &["Folder"],
51        );
52        register_plain_class(
53            "matlab.unittest.fixtures.PathFixture",
54            Some("matlab.unittest.fixtures.Fixture"),
55            &["Path"],
56        );
57        register_plain_class(
58            "matlab.unittest.diagnostics.Diagnostic",
59            None,
60            &["Identifier", "Message"],
61        );
62        register_plain_class("matlab.unittest.constraints.Constraint", None, &[]);
63        for class_name in [
64            "matlab.unittest.constraints.IsEqualTo",
65            "matlab.unittest.constraints.IsTrue",
66            "matlab.unittest.constraints.IsFalse",
67        ] {
68            register_plain_class(
69                class_name,
70                Some("matlab.unittest.constraints.Constraint"),
71                &[],
72            );
73        }
74        register_plain_class(
75            "matlab.unittest.plugins.TestRunnerPlugin",
76            Some("handle"),
77            &[],
78        );
79        register_plain_class(
80            "matlab.unittest.plugins.CodeCoveragePlugin",
81            Some("matlab.unittest.plugins.TestRunnerPlugin"),
82            &["Folders", "IncludingSubfolders"],
83        );
84    });
85}
86
87fn register_test_case() {
88    let methods = qualification_methods()
89        .chain(["addTeardown", "applyFixture", "log"])
90        .map(|name| {
91            (
92                name.to_string(),
93                RuntimeMethod {
94                    name: name.to_string(),
95                    is_static: false,
96                    is_abstract: false,
97                    is_sealed: false,
98                    access: MemberAccess::Public,
99                    function_name: format!("{TEST_CASE_CLASS}.{name}"),
100                    implicit_class_argument: None,
101                },
102            )
103        })
104        .collect();
105    crate::class_registry::register_class(RuntimeClass {
106        name: TEST_CASE_CLASS.into(),
107        parent: Some("handle".into()),
108        properties: properties(&["Name"]),
109        methods,
110    });
111    crate::class_registry::register_class(RuntimeClass {
112        name: FUNCTION_TEST_CASE_CLASS.into(),
113        parent: Some(TEST_CASE_CLASS.into()),
114        properties: HashMap::new(),
115        methods: HashMap::new(),
116    });
117}
118
119fn qualification_methods() -> impl Iterator<Item = &'static str> {
120    [
121        "verifyEqual",
122        "verifyNotEqual",
123        "verifyTrue",
124        "verifyFalse",
125        "verifyGreaterThan",
126        "verifyLessThan",
127        "verifyEmpty",
128        "verifyNotEmpty",
129        "assertEqual",
130        "assertTrue",
131        "assumeEqual",
132        "assumeTrue",
133        "fatalAssertTrue",
134        "verifyThat",
135        "assertThat",
136    ]
137    .into_iter()
138}
139
140fn register_plain_class(name: &str, parent: Option<&str>, property_names: &[&str]) {
141    register_class_with_methods(name, parent, property_names, &[]);
142}
143
144fn register_class_with_methods(
145    name: &str,
146    parent: Option<&str>,
147    property_names: &[&str],
148    method_names: &[&str],
149) {
150    crate::class_registry::register_class(RuntimeClass {
151        name: name.into(),
152        parent: parent.map(str::to_owned),
153        properties: properties(property_names),
154        methods: method_names
155            .iter()
156            .map(|method_name| {
157                (
158                    (*method_name).into(),
159                    RuntimeMethod {
160                        name: (*method_name).into(),
161                        is_static: false,
162                        is_abstract: false,
163                        is_sealed: false,
164                        access: MemberAccess::Public,
165                        function_name: format!("{name}.{method_name}"),
166                        implicit_class_argument: None,
167                    },
168                )
169            })
170            .collect(),
171    });
172}
173
174fn properties(names: &[&str]) -> HashMap<String, RuntimeProperty> {
175    names
176        .iter()
177        .map(|name| {
178            (
179                (*name).into(),
180                RuntimeProperty {
181                    name: (*name).into(),
182                    is_static: false,
183                    is_constant: false,
184                    is_dependent: false,
185                    get_access: MemberAccess::Public,
186                    set_access: MemberAccess::Private,
187                    default_value: Some(Value::String(String::new())),
188                },
189            )
190        })
191        .collect()
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn registers_testing_inheritance_and_qualification_methods() {
200        ensure_testing_classes();
201        assert!(crate::class_registry::is_class_or_subclass(
202            FUNCTION_TEST_CASE_CLASS,
203            TEST_CASE_CLASS
204        ));
205        assert!(crate::class_registry::is_class_or_subclass(
206            TEST_CASE_CLASS,
207            "handle"
208        ));
209        assert!(crate::class_registry::lookup_method(TEST_CASE_CLASS, "verifyEqual").is_some());
210    }
211}