rapydscript-ns 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/PYTHON_DIFFERENCES_REPORT.md +291 -0
  3. package/PYTHON_FEATURE_COVERAGE.md +96 -5
  4. package/README.md +161 -46
  5. package/TODO.md +2 -283
  6. package/language-service/index.js +4474 -0
  7. package/language-service/language-service.d.ts +40 -0
  8. package/package.json +9 -7
  9. package/src/baselib-builtins.pyj +77 -1
  10. package/src/baselib-containers.pyj +8 -4
  11. package/src/baselib-internal.pyj +30 -1
  12. package/src/baselib-str.pyj +8 -1
  13. package/src/lib/collections.pyj +1 -1
  14. package/src/lib/numpy.pyj +10 -10
  15. package/src/monaco-language-service/analyzer.js +131 -9
  16. package/src/monaco-language-service/builtins.js +12 -2
  17. package/src/monaco-language-service/completions.js +170 -1
  18. package/src/monaco-language-service/diagnostics.js +1 -1
  19. package/src/monaco-language-service/index.js +17 -0
  20. package/src/monaco-language-service/scope.js +3 -0
  21. package/src/output/classes.pyj +20 -3
  22. package/src/output/codegen.pyj +1 -1
  23. package/src/output/functions.pyj +4 -16
  24. package/src/output/loops.pyj +0 -9
  25. package/src/output/modules.pyj +1 -4
  26. package/src/output/operators.pyj +14 -0
  27. package/src/output/stream.pyj +0 -13
  28. package/src/parse.pyj +17 -1
  29. package/test/baselib.pyj +4 -4
  30. package/test/classes.pyj +56 -17
  31. package/test/collections.pyj +5 -5
  32. package/test/python_compat.pyj +326 -0
  33. package/test/python_features.pyj +110 -23
  34. package/test/slice.pyj +105 -0
  35. package/test/str.pyj +25 -0
  36. package/test/unit/fixtures/fibonacci_expected.js +1 -1
  37. package/test/unit/index.js +119 -7
  38. package/test/unit/language-service-builtins.js +70 -0
  39. package/test/unit/language-service-bundle.js +5 -5
  40. package/test/unit/language-service-completions.js +180 -0
  41. package/test/unit/language-service-index.js +350 -0
  42. package/test/unit/language-service-scope.js +255 -0
  43. package/test/unit/language-service.js +35 -0
  44. package/test/unit/run-language-service.js +1 -0
  45. package/test/unit/web-repl.js +134 -0
  46. package/tools/build-language-service.js +2 -2
  47. package/tools/compiler.js +0 -24
  48. package/tools/export.js +3 -37
  49. package/web-repl/rapydscript.js +6 -40
  50. package/web-repl/language-service.js +0 -4187
@@ -185,6 +185,84 @@ var TESTS = [
185
185
  js_checks: ["Math.pow(2, 10)", "Math.pow(3, 3)", "Math.pow(10, 0)"],
186
186
  },
187
187
 
188
+ // ── List concatenation ────────────────────────────────────────────────
189
+
190
+ {
191
+ name: "list_concatenation_literals",
192
+ description: "list + list returns a new concatenated list (literal operands)",
193
+ src: [
194
+ "# globals: assrt",
195
+ "result = [1, 2] + [3, 4]",
196
+ "assrt.deepEqual(result, [1, 2, 3, 4])",
197
+ "assrt.equal(result.length, 4)",
198
+ "# originals not mutated",
199
+ "a = [1, 2]",
200
+ "b = [3, 4]",
201
+ "c = a + b",
202
+ "assrt.deepEqual(c, [1, 2, 3, 4])",
203
+ "assrt.deepEqual(a, [1, 2])",
204
+ "assrt.deepEqual(b, [3, 4])",
205
+ ].join("\n"),
206
+ js_checks: ["ρσ_list_add("],
207
+ },
208
+
209
+ {
210
+ name: "list_concatenation_variables",
211
+ description: "list + list works with variable references",
212
+ src: [
213
+ "# globals: assrt",
214
+ "a = [10, 20]",
215
+ "b = [30]",
216
+ "assrt.deepEqual(a + b, [10, 20, 30])",
217
+ "assrt.deepEqual([] + [1], [1])",
218
+ "assrt.deepEqual([1] + [], [1])",
219
+ "assrt.deepEqual([] + [], [])",
220
+ ].join("\n"),
221
+ },
222
+
223
+ {
224
+ name: "list_iadd_extends_in_place",
225
+ description: "list += list extends the list in-place (same object)",
226
+ src: [
227
+ "# globals: assrt",
228
+ "a = [1, 2]",
229
+ "ref = a",
230
+ "a += [3, 4]",
231
+ "assrt.deepEqual(a, [1, 2, 3, 4])",
232
+ "# ref still points to same object, now extended",
233
+ "assrt.deepEqual(ref, [1, 2, 3, 4])",
234
+ "assrt.ok(a is ref)",
235
+ ].join("\n"),
236
+ js_checks: ["ρσ_list_iadd("],
237
+ },
238
+
239
+ {
240
+ name: "list_concat_does_not_break_number_add",
241
+ description: "numbers still add correctly after list-concat helpers are introduced",
242
+ src: [
243
+ "# globals: assrt",
244
+ "assrt.equal(1 + 2, 3)",
245
+ "assrt.equal(3 + 4, 7)",
246
+ "assrt.equal(0 + 0, 0)",
247
+ "x = 10",
248
+ "x += 5",
249
+ "assrt.equal(x, 15)",
250
+ ].join("\n"),
251
+ },
252
+
253
+ {
254
+ name: "list_concat_does_not_break_string_concat",
255
+ description: "string concatenation still works correctly",
256
+ src: [
257
+ "# globals: assrt",
258
+ "assrt.equal('hello' + ' world', 'hello world')",
259
+ "assrt.equal('a' + 'b' + 'c', 'abc')",
260
+ "s = 'foo'",
261
+ "s += 'bar'",
262
+ "assrt.equal(s, 'foobar')",
263
+ ].join("\n"),
264
+ },
265
+
188
266
  {
189
267
  name: "not_operator",
190
268
  description: '"not" compiles to "!"',
@@ -424,8 +502,8 @@ var TESTS = [
424
502
  "increment()",
425
503
  "assrt.equal(counter, 3)",
426
504
  ].join("\n"),
427
- // nonlocal → the outer variable is accessed/modified directly
428
- js_checks: ["counter += 1"],
505
+ // nonlocal → the outer variable is accessed/modified directly via ρσ_list_iadd
506
+ js_checks: ["ρσ_list_iadd(counter,"],
429
507
  },
430
508
 
431
509
  // ── Classes ───────────────────────────────────────────────────────────
@@ -1093,7 +1171,7 @@ assrt.equal(fib(15), 610)
1093
1171
  " return fn(x)",
1094
1172
  "assrt.equal(apply(lambda x: x * x, 5), 25)",
1095
1173
  "nums = [3, 1, 2]",
1096
- "nums.sort(lambda a, b: a - b)",
1174
+ "nums.sort()",
1097
1175
  "assrt.deepEqual(nums, [1, 2, 3])",
1098
1176
  ].join("\n"),
1099
1177
  js_checks: [],
@@ -2664,15 +2742,14 @@ assrt.equal(fib(15), 610)
2664
2742
 
2665
2743
  {
2666
2744
  name: "operator_overloading_no_flag",
2667
- description: "Without overload_operators flag operators emit native JS (no helpers in user code)",
2745
+ description: "Without overload_operators flag: + uses ρσ_list_add (not ρσ_op_add), * is native",
2668
2746
  src: [
2669
2747
  "# globals: assrt",
2670
2748
  "assrt.equal(2 + 3, 5)",
2671
2749
  "assrt.equal(3 * 4, 12)",
2672
2750
  ].join("\n"),
2673
- // Verify user-code expressions compile to native operators, not helper calls
2674
- js_checks: [/assrt\.equal\(2 \+ 3, 5\)/, /assrt\.equal\(3 \* 4, 12\)/],
2675
- js_not_checks: [],
2751
+ // + should compile to ρσ_list_add (lightweight list/number/string helper)
2752
+ js_checks: ["ρσ_list_add(2, 3)", /assrt\.equal\(3 \* 4, 12\)/],
2676
2753
  },
2677
2754
 
2678
2755
  {
@@ -2874,6 +2951,41 @@ assrt.equal(fib(15), 610)
2874
2951
  },
2875
2952
  },
2876
2953
 
2954
+ {
2955
+ name: "python_flag_truthiness_via_scoped_flags",
2956
+ description: "truthiness flag via scoped_flags wraps if-conditions with ρσ_bool(; plain code does not",
2957
+ run: function() {
2958
+ var src = "if x:\n pass";
2959
+ var src_inline = "from __python__ import truthiness\n" + src;
2960
+ var js_inline = compile(src_inline);
2961
+ var js_flagged = compile_with_flags(src, { truthiness: true });
2962
+ var js_plain = compile(src);
2963
+ assert.ok(/if\s*\(ρσ_bool\(/.test(js_inline),
2964
+ "inline import: expected if(ρσ_bool( in: " + js_inline);
2965
+ assert.ok(/if\s*\(ρσ_bool\(/.test(js_flagged),
2966
+ "scoped_flags: expected if(ρσ_bool( in: " + js_flagged);
2967
+ assert.ok(!/if\s*\(ρσ_bool\(/.test(js_plain),
2968
+ "no flag: if(ρσ_bool( should NOT appear in: " + js_plain);
2969
+ },
2970
+ },
2971
+
2972
+ {
2973
+ name: "python_flag_truthiness_via_python_flags_option",
2974
+ description: "truthiness passed as python_flags string to embedded_compiler wraps if-conditions",
2975
+ run: function() {
2976
+ var make_ec = require("../../tools/embedded_compiler.js");
2977
+ var src = "if x:\n pass";
2978
+ var ec_with = make_ec(RapydScript, baselib, null);
2979
+ var js_with = ec_with.compile(src, { python_flags: "truthiness" });
2980
+ assert.ok(/if\s*\(ρσ_bool\(/.test(js_with),
2981
+ "python_flags='truthiness': expected if(ρσ_bool( in: " + js_with);
2982
+ var ec_without = make_ec(RapydScript, baselib, null);
2983
+ var js_without = ec_without.compile(src, {});
2984
+ assert.ok(!/if\s*\(ρσ_bool\(/.test(js_without),
2985
+ "no python_flags: if(ρσ_bool( should NOT appear in: " + js_without);
2986
+ },
2987
+ },
2988
+
2877
2989
  {
2878
2990
  name: "python_flag_all_flags_runtime",
2879
2991
  description: "overload_operators + overload_getitem work correctly at runtime via scoped_flags",
@@ -734,6 +734,76 @@ function make_tests(BuiltinsRegistry, BuiltinInfo, HoverEngine, SignatureHelpEng
734
734
  },
735
735
  },
736
736
 
737
+ // ── slice builtin ─────────────────────────────────────────────────
738
+
739
+ {
740
+ name: "slice_registered_as_class",
741
+ description: "slice is registered in BuiltinsRegistry with kind='class'",
742
+ run: function () {
743
+ var reg = new BuiltinsRegistry();
744
+ var bi = reg.get('slice');
745
+ assert.ok(bi, 'slice should be registered');
746
+ assert.strictEqual(bi.name, 'slice');
747
+ assert.strictEqual(bi.kind, 'class');
748
+ assert.ok(Array.isArray(bi.params));
749
+ assert.ok(bi.doc && bi.doc.length > 0, 'slice should have a docstring');
750
+ },
751
+ },
752
+
753
+ {
754
+ name: "slice_hover_markdown",
755
+ description: "slice hover markdown includes signature and doc",
756
+ run: function () {
757
+ var reg = new BuiltinsRegistry();
758
+ var md = reg.getHoverMarkdown('slice');
759
+ assert.ok(md, 'slice should have hover markdown');
760
+ assert.ok(md.indexOf('slice') !== -1, 'hover should mention slice');
761
+ assert.ok(md.indexOf('start_or_stop') !== -1, 'hover should mention start_or_stop param');
762
+ },
763
+ },
764
+
765
+ {
766
+ name: "slice_in_completions",
767
+ description: "slice appears in completion list as a built-in class",
768
+ run: function () {
769
+ var reg = new BuiltinsRegistry();
770
+ var analyzer = new SourceAnalyzer(RS);
771
+ var engine = new CompletionEngine(analyzer, {
772
+ virtualFiles: {},
773
+ builtinNames: ['slice'],
774
+ builtinsRegistry: reg,
775
+ });
776
+ var list = engine.getCompletions(null, pos(1, 6), 'slice', MockKind);
777
+ var item = list.suggestions.find(function (s) { return s.label === 'slice'; });
778
+ assert.ok(item, 'slice should appear in completions');
779
+ assert.strictEqual(item.kind, MockKind.Class, 'slice should have Class kind');
780
+ },
781
+ },
782
+
783
+ {
784
+ name: "slice_signature_help",
785
+ description: "slice signature help returns start_or_stop, stop, step params",
786
+ run: function () {
787
+ var reg = new BuiltinsRegistry();
788
+ var info = reg.getSignatureInfo('slice');
789
+ assert.ok(info, 'slice should have signature info');
790
+ assert.ok(info.label.indexOf('slice') !== -1, 'label should contain slice');
791
+ assert.ok(info.params.length >= 1, 'should have at least 1 param');
792
+ assert.strictEqual(info.params[0].label, 'start_or_stop: int');
793
+ },
794
+ },
795
+
796
+ {
797
+ name: "slice_in_getNames",
798
+ description: "slice appears in BuiltinsRegistry.getNames()",
799
+ run: function () {
800
+ var reg = new BuiltinsRegistry();
801
+ var names = reg.getNames();
802
+ assert.ok(names.indexOf('slice') !== -1,
803
+ 'slice should be in getNames(), got: ' + names.join(', '));
804
+ },
805
+ },
806
+
737
807
  ];
738
808
 
739
809
  return TESTS;
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * test/unit/language-service-bundle.js
3
3
  *
4
- * Verifies that the built web-repl/language-service.js can be loaded as an
4
+ * Verifies that the built language-service/index.js can be loaded as an
5
5
  * ES module without errors (e.g. duplicate top-level declarations).
6
6
  *
7
7
  * Usage:
@@ -15,11 +15,11 @@ var fs = require("fs");
15
15
  var utils = require("../../tools/utils");
16
16
  var colored = utils.safe_colored;
17
17
 
18
- var bundle_path = path.join(__dirname, "../../web-repl/language-service.js");
18
+ var bundle_path = path.join(__dirname, "../../language-service/index.js");
19
19
 
20
20
  if (!fs.existsSync(bundle_path)) {
21
21
  console.error(colored("SKIP language_service_bundle_loads", "yellow") +
22
- " – web-repl/language-service.js not found; run: npm run build:ls");
22
+ " – language-service/index.js not found; run: npm run build:ls");
23
23
  process.exit(0);
24
24
  }
25
25
 
@@ -41,7 +41,7 @@ import(bundle_url).then(function (mod) {
41
41
 
42
42
  // Test 1: module loads without parse/runtime errors (implicit — we got here)
43
43
  pass("language_service_bundle_loads",
44
- "web-repl/language-service.js loads as an ES module without errors");
44
+ "language-service/index.js loads as an ES module without errors");
45
45
 
46
46
  // Test 2: registerRapydScript is exported
47
47
  try {
@@ -75,7 +75,7 @@ import(bundle_url).then(function (mod) {
75
75
 
76
76
  }).catch(function (e) {
77
77
  console.log(colored("FAIL language_service_bundle_loads", "red") +
78
- " \u2013 web-repl/language-service.js failed to load as an ES module");
78
+ " \u2013 language-service/index.js failed to load as an ES module");
79
79
  console.log(" " + (e.message || String(e)));
80
80
  console.log("");
81
81
  console.log(colored("1 test(s) failed.", "red"));
@@ -1097,6 +1097,186 @@ function make_tests(CompletionEngine, detect_context, SourceAnalyzer, DtsRegistr
1097
1097
  },
1098
1098
  },
1099
1099
 
1100
+ // ── Return-type inference ─────────────────────────────────────────
1101
+
1102
+ {
1103
+ name: "return_type_local_fn_list_annotation",
1104
+ description: "def fn() -> [str]: — call result completions include list members",
1105
+ run: function () {
1106
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1107
+ var engine = make_engine({}, [], null, builtins_mod);
1108
+ var analyzer = new SourceAnalyzer(RS);
1109
+ var scopeMap = analyzer.analyze([
1110
+ "def getAllServers() -> [str]:",
1111
+ " return []",
1112
+ "pass",
1113
+ ].join("\n"), {});
1114
+
1115
+ // fn().l — call_result context
1116
+ var list = engine.getCompletions(scopeMap, pos(3, 18), "getAllServers().", MockKind);
1117
+ assert_has(list, 'length', 'list.length via call_result return type');
1118
+ assert_has(list, 'append', 'list.append via call_result return type');
1119
+ },
1120
+ },
1121
+
1122
+ {
1123
+ name: "return_type_local_fn_dot_var",
1124
+ description: "x = fn() where fn() -> [str] — x. completions include list members",
1125
+ run: function () {
1126
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1127
+ var engine = make_engine({}, [], null, builtins_mod);
1128
+ var analyzer = new SourceAnalyzer(RS);
1129
+ var scopeMap = analyzer.analyze([
1130
+ "def getAllServers() -> [str]:",
1131
+ " return []",
1132
+ "servers = getAllServers()",
1133
+ "pass",
1134
+ ].join("\n"), {});
1135
+
1136
+ var list = engine.getCompletions(scopeMap, pos(4, 9), "servers.", MockKind);
1137
+ assert_has(list, 'length', 'list.length on var assigned from annotated fn');
1138
+ assert_has(list, 'append', 'list.append on var assigned from annotated fn');
1139
+ },
1140
+ },
1141
+
1142
+ {
1143
+ name: "return_type_imported_fn_call_result",
1144
+ description: "getAllServers().l — imported fn with -> [str] annotation suggests list members",
1145
+ run: function () {
1146
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1147
+ var servers_src = [
1148
+ "def getAllServers() -> [str]:",
1149
+ " return []",
1150
+ ].join("\n");
1151
+ var engine = make_engine({ servers: servers_src }, [], null, builtins_mod);
1152
+ var analyzer = new SourceAnalyzer(RS);
1153
+ var scopeMap = analyzer.analyze([
1154
+ "from servers import getAllServers",
1155
+ "pass",
1156
+ ].join("\n"), {});
1157
+
1158
+ // getAllServers().l — call_result context
1159
+ var list = engine.getCompletions(scopeMap, pos(2, 18), "getAllServers().", MockKind);
1160
+ assert_has(list, 'length', 'list.length via cross-file return type (call_result)');
1161
+ assert_has(list, 'append', 'list.append via cross-file return type (call_result)');
1162
+ },
1163
+ },
1164
+
1165
+ {
1166
+ name: "return_type_imported_fn_dot_var",
1167
+ description: "x = getAllServers() from import — x. includes list members",
1168
+ run: function () {
1169
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1170
+ var servers_src = [
1171
+ "def getAllServers() -> [str]:",
1172
+ " return []",
1173
+ ].join("\n");
1174
+ var engine = make_engine({ servers: servers_src }, [], null, builtins_mod);
1175
+ var analyzer = new SourceAnalyzer(RS);
1176
+ var scopeMap = analyzer.analyze([
1177
+ "from servers import getAllServers",
1178
+ "servers = getAllServers()",
1179
+ "pass",
1180
+ ].join("\n"), {});
1181
+
1182
+ var list = engine.getCompletions(scopeMap, pos(3, 10), "servers.", MockKind);
1183
+ assert_has(list, 'length', 'list.length on var from cross-file fn');
1184
+ assert_has(list, 'append', 'list.append on var from cross-file fn');
1185
+ },
1186
+ },
1187
+
1188
+ // ── Inferred return type for imported functions (no annotation) ───────
1189
+
1190
+ {
1191
+ name: "return_type_imported_fn_inferred_call_result",
1192
+ description: "imported fn with no annotation, return [] — call result completions include list members",
1193
+ run: function () {
1194
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1195
+ var servers_src = [
1196
+ "def getAllServers():",
1197
+ " return []",
1198
+ ].join("\n");
1199
+ var engine = make_engine({ servers: servers_src }, [], null, builtins_mod);
1200
+ var analyzer = new SourceAnalyzer(RS);
1201
+ var scopeMap = analyzer.analyze([
1202
+ "from servers import getAllServers",
1203
+ "pass",
1204
+ ].join("\n"), {});
1205
+
1206
+ var list = engine.getCompletions(scopeMap, pos(2, 18), "getAllServers().", MockKind);
1207
+ assert_has(list, 'length', 'list.length via inferred cross-file return type (call_result)');
1208
+ assert_has(list, 'append', 'list.append via inferred cross-file return type (call_result)');
1209
+ },
1210
+ },
1211
+
1212
+ {
1213
+ name: "return_type_imported_fn_inferred_dot_var",
1214
+ description: "x = fn() from import, fn returns [] — x. includes list members",
1215
+ run: function () {
1216
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1217
+ var servers_src = [
1218
+ "def getAllServers():",
1219
+ " return []",
1220
+ ].join("\n");
1221
+ var engine = make_engine({ servers: servers_src }, [], null, builtins_mod);
1222
+ var analyzer = new SourceAnalyzer(RS);
1223
+ var scopeMap = analyzer.analyze([
1224
+ "from servers import getAllServers",
1225
+ "servers = getAllServers()",
1226
+ "pass",
1227
+ ].join("\n"), {});
1228
+
1229
+ var list = engine.getCompletions(scopeMap, pos(3, 10), "servers.", MockKind);
1230
+ assert_has(list, 'length', 'list.length on var from inferred cross-file fn');
1231
+ assert_has(list, 'append', 'list.append on var from inferred cross-file fn');
1232
+ },
1233
+ },
1234
+
1235
+ {
1236
+ name: "return_type_imported_fn_inferred_dict",
1237
+ description: "imported fn with return {} — call result completions include dict members",
1238
+ run: function () {
1239
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1240
+ var utils_src = [
1241
+ "def get_config():",
1242
+ " return {}",
1243
+ ].join("\n");
1244
+ var engine = make_engine({ utils: utils_src }, [], null, builtins_mod);
1245
+ var analyzer = new SourceAnalyzer(RS);
1246
+ var scopeMap = analyzer.analyze([
1247
+ "from utils import get_config",
1248
+ "pass",
1249
+ ].join("\n"), {});
1250
+
1251
+ var list = engine.getCompletions(scopeMap, pos(2, 14), "get_config().", MockKind);
1252
+ assert_has(list, 'keys', 'dict.keys via inferred cross-file return type');
1253
+ assert_has(list, 'values', 'dict.values via inferred cross-file return type');
1254
+ },
1255
+ },
1256
+
1257
+ {
1258
+ name: "return_type_imported_fn_inferred_consistent_branches",
1259
+ description: "imported fn with multiple return [] branches — type still inferred as list",
1260
+ run: function () {
1261
+ var builtins_mod = require(path.join(__dirname, '../../src/monaco-language-service/builtins.js'));
1262
+ var utils_src = [
1263
+ "def get_items(flag):",
1264
+ " if flag:",
1265
+ " return []",
1266
+ " return []",
1267
+ ].join("\n");
1268
+ var engine = make_engine({ utils: utils_src }, [], null, builtins_mod);
1269
+ var analyzer = new SourceAnalyzer(RS);
1270
+ var scopeMap = analyzer.analyze([
1271
+ "from utils import get_items",
1272
+ "pass",
1273
+ ].join("\n"), {});
1274
+
1275
+ var list = engine.getCompletions(scopeMap, pos(2, 12), "get_items().", MockKind);
1276
+ assert_has(list, 'append', 'list.append via inferred multi-branch import');
1277
+ },
1278
+ },
1279
+
1100
1280
  ];
1101
1281
 
1102
1282
  return TESTS;