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}