microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/sim

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc_frontend/src/compile/tests/multiple_packages.rs

604lines · modecode

1use std::sync::Arc;
2
3use super::{compile, PackageStore, SourceMap};
4use crate::compile::TargetCapabilityFlags;
5
6use crate::compile::core;
7use expect_test::expect;
8use expect_test::Expect;
9use indoc::indoc;
10use qsc_data_structures::language_features::LanguageFeatures;
11use qsc_hir::hir::PackageId;
12
13/// Runs a test where each successive package relies solely on the package before it
14/// useful for testing chains of reexports
15fn multiple_package_check(packages: Vec<(&str, &str)>) {
16 multiple_package_check_inner(packages, None);
17}
18
19fn multiple_package_check_expect_err(packages: Vec<(&str, &str)>, expect: &Expect) {
20 multiple_package_check_inner(packages, Some(expect));
21}
22
23fn multiple_package_check_inner(packages: Vec<(&str, &str)>, expect: Option<&Expect>) {
24 let mut store = PackageStore::new(core());
25 let mut prev_id_and_name: Option<(PackageId, &str)> = None;
26 let num_packages = packages.len();
27 for (ix, (package_name, package_source)) in packages.into_iter().enumerate() {
28 let is_last = ix == num_packages - 1;
29 let deps = if let Some((prev_id, prev_name)) = prev_id_and_name {
30 vec![(prev_id, Some(Arc::from(prev_name)))]
31 } else {
32 vec![]
33 };
34
35 let sources = SourceMap::new(
36 [(
37 Arc::from(format!("{package_name}.qs")),
38 Arc::from(package_source),
39 )],
40 None,
41 );
42
43 let unit = compile(
44 &store,
45 &deps[..],
46 sources,
47 TargetCapabilityFlags::all(),
48 LanguageFeatures::default(),
49 );
50
51 match (is_last, &expect) {
52 (true, Some(expect)) => {
53 expect.assert_eq(&format!("{:#?}", unit.errors));
54 }
55 _ => {
56 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
57 }
58 }
59
60 prev_id_and_name = Some((store.insert(unit), package_name));
61 }
62}
63
64/// This can be used to test multiple packages which internally have multiple source files, as opposed to the more simple `multiple_package_check`
65/// which only allows one source file per package (for easy and quick test creation).
66fn multiple_package_multiple_source_check(
67 packages: Vec<(&str, Vec<(&str, &str)>)>,
68 expect: Option<&Expect>,
69) {
70 let mut store = PackageStore::new(core());
71 let mut prev_id_and_name: Option<(PackageId, &str)> = None;
72 let num_packages = packages.len();
73 for (ix, (package_name, sources)) in packages.into_iter().enumerate() {
74 let is_last = ix == num_packages - 1;
75 let deps = if let Some((prev_id, prev_name)) = prev_id_and_name {
76 vec![(prev_id, Some(Arc::from(prev_name)))]
77 } else {
78 vec![]
79 };
80
81 let sources = SourceMap::new(
82 sources.iter().map(|(name, source)| {
83 (
84 Arc::from(format!("{package_name}/{name}.qs")),
85 Arc::from(*source),
86 )
87 }),
88 None,
89 );
90
91 let unit = compile(
92 &store,
93 &deps[..],
94 sources,
95 TargetCapabilityFlags::all(),
96 LanguageFeatures::default(),
97 );
98
99 match (is_last, &expect) {
100 (true, Some(expect)) => {
101 expect.assert_eq(&format!("{:#?}", unit.errors));
102 }
103 _ => {
104 assert!(unit.errors.is_empty(), "{:#?}", unit.errors);
105 }
106 }
107
108 prev_id_and_name = Some((store.insert(unit), package_name));
109 }
110}
111
112#[test]
113fn namespace_named_main_doesnt_create_main_namespace() {
114 multiple_package_check_expect_err(
115 vec![
116 (
117 "Main",
118 "operation Foo(x: Int, y: Bool) : Int {
119 x
120 }
121 export Foo;",
122 ),
123 (
124 "C",
125 r#"
126 // this fails because `Main` is considered the "root"
127 import Main.Main.Foo;
128 @EntryPoint()
129 operation Main() : Unit {
130 Foo(10, true);
131 }"#,
132 ),
133 ],
134 &expect!([r#"
135 [
136 Error(
137 Resolve(
138 NotFound(
139 "Main.Main.Foo",
140 Span {
141 lo: 86,
142 hi: 99,
143 },
144 ),
145 ),
146 ),
147 Error(
148 Resolve(
149 NotFound(
150 "Foo",
151 Span {
152 lo: 205,
153 hi: 208,
154 },
155 ),
156 ),
157 ),
158 Error(
159 Type(
160 Error(
161 AmbiguousTy(
162 Span {
163 lo: 205,
164 hi: 218,
165 },
166 ),
167 ),
168 ),
169 ),
170 ]"#]),
171 );
172}
173
174#[test]
175fn namespaces_named_main_treated_as_root() {
176 multiple_package_check(vec![
177 (
178 "Main",
179 "operation Foo(x: Int, y: Bool) : Int {
180 x
181 }
182 export Foo;",
183 ),
184 (
185 "C",
186 "
187 // note that this is not Main.Main
188 // and that the namespace `Main` is omitted here
189 import Main.Foo;
190 @EntryPoint()
191 operation Main() : Unit {
192 Foo(10, true);
193 }",
194 ),
195 ]);
196}
197
198#[test]
199fn multiple_packages_reference_exports() {
200 multiple_package_check(vec![
201 (
202 "PackageA",
203 indoc! {"
204 operation Foo(x: Int, y: Bool) : Int {
205 x
206 }
207 export Foo;
208 "},
209 ),
210 (
211 "PackageB",
212 indoc! {"
213 import PackageA.PackageA.Foo;
214 export Foo;
215 "},
216 ),
217 (
218 "PackageC",
219 indoc! {"
220 import PackageB.PackageB.Foo;
221 @EntryPoint()
222 operation Main() : Unit {
223 Foo(10, true);
224 }
225 "},
226 ),
227 ]);
228}
229
230#[test]
231#[allow(clippy::too_many_lines)]
232fn multiple_packages_disallow_unexported_imports() {
233 multiple_package_check_expect_err(
234 vec![
235 (
236 "PackageA",
237 indoc! {"
238 function FunctionA() : Int {
239 1
240 }
241 "},
242 ),
243 (
244 "PackageB",
245 indoc! {"
246 import PackageA.PackageA.FunctionA;
247 @EntryPoint()
248 function Main() : Unit {
249 FunctionA();
250 }
251 "},
252 ),
253 ],
254 &expect![[r#"
255 [
256 Error(
257 Resolve(
258 NotFound(
259 "PackageA.PackageA.FunctionA",
260 Span {
261 lo: 7,
262 hi: 34,
263 },
264 ),
265 ),
266 ),
267 Error(
268 Resolve(
269 NotFound(
270 "FunctionA",
271 Span {
272 lo: 78,
273 hi: 87,
274 },
275 ),
276 ),
277 ),
278 Error(
279 Type(
280 Error(
281 AmbiguousTy(
282 Span {
283 lo: 78,
284 hi: 89,
285 },
286 ),
287 ),
288 ),
289 ),
290 ]"#]],
291 );
292}
293
294#[test]
295fn reexport() {
296 multiple_package_check(vec![
297 (
298 "PackageA",
299 indoc! {"
300 export Std.Core.Length as Foo;
301 "},
302 ),
303 (
304 "PackageB",
305 indoc! {"
306
307 import PackageA.PackageA.Foo;
308 @EntryPoint()
309 function Main() : Unit {
310 use qs = Qubit[2];
311 let len = Foo(qs);
312 }
313 "},
314 ),
315 ]);
316}
317
318#[test]
319fn reexport_export_has_alias() {
320 multiple_package_check(vec![
321 (
322 "PackageA",
323 indoc! {"
324 operation Foo(x: Int, y: Bool) : Int {
325 x
326 }
327 export Foo as Bar;
328 "},
329 ),
330 (
331 "PackageB",
332 indoc! {"
333 import PackageA.PackageA.Bar;
334 "},
335 ),
336 ]);
337}
338
339#[test]
340fn reexport_import_has_alias() {
341 multiple_package_check(vec![
342 (
343 "PackageA",
344 "operation Foo(x: Int, y: Bool) : Int {
345 x
346 }
347 export Foo;
348 ",
349 ),
350 (
351 "PackageB",
352 "
353 import PackageA.PackageA.Foo as Bar;
354
355 export Bar;
356 ",
357 ),
358 ]);
359}
360
361#[test]
362fn reexport_reexport_has_alias() {
363 multiple_package_check(vec![
364 (
365 "PackageA",
366 "
367 operation Foo(x: Int, y: Bool) : Int {
368 x
369 }
370 export Foo;
371 ",
372 ),
373 (
374 "PackageB",
375 "
376 import PackageA.PackageA.Foo;
377 export Foo as Bar;
378 ",
379 ),
380 (
381 "PackageC",
382 "
383 import PackageB.PackageB.Bar;
384 @EntryPoint()
385 operation Main() : Unit {
386 Bar(10, true);
387 }
388 ",
389 ),
390 ]);
391}
392
393#[test]
394fn reexport_callable_combined_aliases() {
395 multiple_package_check(vec![
396 (
397 "PackageA",
398 "
399 operation Foo(x: Int, y: Bool) : Int {
400 x
401 }
402 export Foo;
403 ",
404 ),
405 (
406 "PackageB",
407 "
408 import PackageA.PackageA.Foo;
409 import PackageA.PackageA.Foo as Foo2;
410 export Foo, Foo as Bar, Foo2, Foo2 as Bar2;
411 ",
412 ),
413 (
414 "PackageC",
415 "
416 import PackageB.PackageB.Foo, PackageB.PackageB.Bar, PackageB.PackageB.Foo2, PackageB.PackageB.Bar2;
417 @EntryPoint()
418 operation Main() : Unit {
419 Foo(10, true);
420 Foo2(10, true);
421 Bar(10, true);
422 Bar2(10, true);
423 }
424 ",
425 ),
426 ]);
427}
428
429#[test]
430fn direct_reexport() {
431 multiple_package_check(vec![
432 (
433 "A",
434 "operation Foo(x: Int, y: Bool) : Int {
435 x
436 }
437 export Foo as Bar;",
438 ),
439 ("B", "export A.A.Bar as Baz;"),
440 (
441 "C",
442 "import B.B.Baz as Quux;
443 @EntryPoint()
444 operation Main() : Unit {
445 Quux(10, true);
446 }",
447 ),
448 ]);
449}
450
451#[test]
452fn reexports_still_type_check() {
453 multiple_package_check_expect_err(
454 vec![
455 (
456 "A",
457 "operation Foo(x: Int, y: Bool) : Int {
458 x
459 }
460 export Foo as Bar;",
461 ),
462 (
463 "B",
464 "
465 export A.A.Bar as Baz;",
466 ),
467 (
468 "C",
469 "import B.B.Baz as Quux;
470 @EntryPoint()
471 operation Main() : Unit {
472 Quux(10, 10);
473 }",
474 ),
475 ],
476 &expect![[r#"
477 [
478 Error(
479 Type(
480 Error(
481 TyMismatch(
482 "Bool",
483 "Int",
484 Span {
485 lo: 128,
486 hi: 140,
487 },
488 ),
489 ),
490 ),
491 ),
492 ]"#]],
493 );
494}
495
496#[test]
497fn namespaces_named_lowercase_main_not_treated_as_root() {
498 multiple_package_check(vec![
499 (
500 "main",
501 "operation Foo(x: Int, y: Bool) : Int {
502 x
503 }
504 export Foo;",
505 ),
506 (
507 "C",
508 "
509 import main.main.Foo;
510 @EntryPoint()
511 operation Main() : Unit {
512 Foo(10, true);
513 }",
514 ),
515 ]);
516}
517
518#[test]
519fn aliased_export_via_aliased_import() {
520 multiple_package_check(vec![
521 (
522 "MyGithubLibrary",
523 r#"
524 namespace TestPackage {
525
526 import Subpackage.Subpackage.Hello as SubHello;
527
528 export HelloFromGithub;
529 export SubHello;
530
531 /// This is a Doc String!
532 function HelloFromGithub() : Unit {
533 SubHello();
534 }
535 }
536
537 namespace Subpackage.Subpackage {
538 function Hello() : Unit {}
539 export Hello;
540 }
541
542 "#,
543 ),
544 (
545 "UserCode",
546 r#"
547 import MyGithubLibrary.TestPackage.SubHello;
548 import MyGithubLibrary.TestPackage.HelloFromGithub;
549 import MyGithubLibrary.Subpackage.Subpackage as P;
550
551 function Main() : Unit {
552 HelloFromGithub();
553 SubHello();
554 P.Hello();
555 }
556 "#,
557 ),
558 ]);
559}
560
561#[test]
562fn udt_reexport_with_alias() {
563 multiple_package_multiple_source_check(
564 vec![
565 (
566 "A",
567 vec![
568 ("FileOne", "struct Foo { content: Bool }"),
569 ("FileTwo", "export FileOne.Foo as Bar;"),
570 ],
571 ),
572 ("B", vec![("FileThree", "export A.FileTwo.Bar as Baz;")]),
573 (
574 "C",
575 vec![(
576 "FileFour",
577 "@EntryPoint()
578 operation Main() : Unit {
579 let x = new B.FileThree.Baz { content = true };
580 }",
581 )],
582 ),
583 ],
584 Some(&expect!["[]"]),
585 );
586}
587
588#[test]
589fn callable_reexport() {
590 multiple_package_check(vec![
591 (
592 "A",
593 "function Foo() : Unit { }
594 export Foo as Bar;",
595 ),
596 (
597 "B",
598 " @EntryPoint()
599 operation Main() : Unit {
600 let x = A.A.Bar();
601 }",
602 ),
603 ]);
604}
605