microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/qiskit2-explore

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc/src/packages/tests.rs

344lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3use crate::{LanguageFeatures, TargetCapabilityFlags, compile};
4use expect_test::expect;
5use qsc_frontend::compile::{CompileUnit, SourceMap};
6use qsc_passes::PackageType;
7use qsc_project::{PackageInfo, Project, ProjectType};
8use rustc_hash::FxHashMap;
9use std::sync::Arc;
10
11fn mock_program() -> Project {
12 // Mock data for the ProgramConfig
13 let package_graph_sources = qsc_project::PackageGraphSources {
14 root: qsc_project::PackageInfo {
15 sources: vec![(
16 Arc::from("test.qs"),
17 Arc::from("@EntryPoint() operation Main() : Unit {}"),
18 )],
19 language_features: LanguageFeatures::default(),
20 dependencies: FxHashMap::from_iter(vec![(
21 Arc::from("SomeLibraryAlias"),
22 Arc::from("SomeLibraryKey"),
23 )]),
24 package_type: Some(qsc_project::PackageType::Exe),
25 },
26 packages: FxHashMap::from_iter(vec![(
27 Arc::from("SomeLibraryKey"),
28 PackageInfo {
29 sources: vec![(
30 Arc::from("librarymain"),
31 Arc::from("operation LibraryMain() : Unit {} export LibraryMain;"),
32 )],
33 language_features: LanguageFeatures::default(),
34 dependencies: FxHashMap::default(),
35 package_type: Some(qsc_project::PackageType::Lib),
36 },
37 )]),
38 has_manifest: true,
39 };
40
41 Project {
42 lints: vec![],
43 errors: vec![],
44 path: "project/qsharp.json".into(),
45 name: "project".into(),
46 project_type: qsc_project::ProjectType::QSharp(package_graph_sources),
47 target_profile: Some(qsc_data_structures::target::Profile::Unrestricted),
48 }
49}
50
51#[test]
52fn test_prepare_package_store() {
53 let program = mock_program();
54 let ProjectType::QSharp(package_graph_sources) = program.project_type else {
55 panic!("project should be a Q# project");
56 };
57 let buildable_program =
58 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
59
60 expect![[r"
61 []
62 "]]
63 .assert_debug_eq(&buildable_program.dependency_errors);
64
65 // compile the user code
66 let compiled = compile::compile(
67 &buildable_program.store,
68 &buildable_program.user_code_dependencies[..],
69 SourceMap::new(buildable_program.user_code.sources, None),
70 PackageType::Exe,
71 TargetCapabilityFlags::default(),
72 LanguageFeatures::default(),
73 );
74
75 let CompileUnit {
76 package,
77 ast,
78 errors,
79 ..
80 } = compiled.0;
81
82 expect![[r#"
83 Package:
84 entry expression: Expr 8 [0-0] [Type Unit]: Call:
85 Expr 7 [24-28] [Type Unit]: Var: Item 1
86 Expr 6 [28-30] [Type Unit]: Unit
87 Item 0 [0-40] (Public):
88 Namespace (Ident 5 [0-40] "test"): Item 1
89 Item 1 [0-40] (Internal):
90 Parent: 0
91 EntryPoint
92 Callable 0 [14-40] (operation):
93 name: Ident 1 [24-28] "Main"
94 input: Pat 2 [28-30] [Type Unit]: Unit
95 output: Unit
96 functors: empty set
97 body: SpecDecl 3 [14-40]: Impl:
98 Block 4 [38-40]: <empty>
99 adj: <none>
100 ctl: <none>
101 ctl-adj: <none>"#]]
102 .assert_eq(&package.to_string());
103 expect![[r#"
104 Package 0:
105 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
106 Item 3 [0-40]:
107 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
108 Expr 6 [11-13]: Unit
109 Callable 7 [14-40] (Operation):
110 name: Ident 8 [24-28] "Main"
111 input: Pat 9 [28-30]: Unit
112 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
113 body: Block: Block 13 [38-40]: <empty>"#]]
114 .assert_eq(&ast.package.to_string());
115 expect![[r"
116 []
117 "]]
118 .assert_debug_eq(&errors);
119}
120
121// if there are inconsequential errors in the dependency compilation process, we don't want to
122// abort compilation. This way, we can still show the user some diagnostics.
123
124#[test]
125fn missing_dependency_doesnt_force_failure() {
126 let program = mock_program();
127 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
128 panic!("project should be a Q# project");
129 };
130 package_graph_sources
131 .root
132 .dependencies
133 .insert("NonExistent".into(), "nonexistent-dep-key".into());
134
135 let buildable_program =
136 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
137
138 expect![[r"
139 []
140 "]]
141 .assert_debug_eq(&buildable_program.dependency_errors);
142
143 // compile the user code
144 let compiled = compile::compile(
145 &buildable_program.store,
146 &buildable_program.user_code_dependencies[..],
147 SourceMap::new(buildable_program.user_code.sources, None),
148 PackageType::Exe,
149 TargetCapabilityFlags::default(),
150 LanguageFeatures::default(),
151 );
152
153 let CompileUnit {
154 package,
155 ast,
156 errors,
157 ..
158 } = compiled.0;
159
160 expect![[r#"
161 Package:
162 entry expression: Expr 8 [0-0] [Type Unit]: Call:
163 Expr 7 [24-28] [Type Unit]: Var: Item 1
164 Expr 6 [28-30] [Type Unit]: Unit
165 Item 0 [0-40] (Public):
166 Namespace (Ident 5 [0-40] "test"): Item 1
167 Item 1 [0-40] (Internal):
168 Parent: 0
169 EntryPoint
170 Callable 0 [14-40] (operation):
171 name: Ident 1 [24-28] "Main"
172 input: Pat 2 [28-30] [Type Unit]: Unit
173 output: Unit
174 functors: empty set
175 body: SpecDecl 3 [14-40]: Impl:
176 Block 4 [38-40]: <empty>
177 adj: <none>
178 ctl: <none>
179 ctl-adj: <none>"#]]
180 .assert_eq(&package.to_string());
181 expect![[r#"
182 Package 0:
183 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
184 Item 3 [0-40]:
185 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
186 Expr 6 [11-13]: Unit
187 Callable 7 [14-40] (Operation):
188 name: Ident 8 [24-28] "Main"
189 input: Pat 9 [28-30]: Unit
190 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
191 body: Block: Block 13 [38-40]: <empty>"#]]
192 .assert_eq(&ast.package.to_string());
193 expect![[r"
194 []
195 "]]
196 .assert_debug_eq(&errors);
197}
198
199#[allow(clippy::too_many_lines)]
200#[test]
201fn dependency_error() {
202 let program = mock_program();
203 // Inject a syntax error into one of the dependencies
204 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
205 panic!("project should be a Q# project");
206 };
207 package_graph_sources
208 .packages
209 .values_mut()
210 .next()
211 .expect("expected at least one dependency in the mock program")
212 .sources[0]
213 .1 = "broken_syntax".into();
214
215 let buildable_program =
216 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
217
218 expect![[r#"
219 [
220 WithSource {
221 sources: [
222 Source {
223 name: "librarymain",
224 contents: "broken_syntax",
225 offset: 0,
226 },
227 ],
228 error: Frontend(
229 Error(
230 Parse(
231 Error(
232 Token(
233 Eof,
234 Ident,
235 Span {
236 lo: 0,
237 hi: 13,
238 },
239 ),
240 ),
241 ),
242 ),
243 ),
244 },
245 ]
246 "#]]
247 .assert_debug_eq(&buildable_program.dependency_errors);
248
249 // compile the user code
250 let compiled = compile::compile(
251 &buildable_program.store,
252 &buildable_program.user_code_dependencies[..],
253 SourceMap::new(buildable_program.user_code.sources, None),
254 PackageType::Exe,
255 TargetCapabilityFlags::default(),
256 LanguageFeatures::default(),
257 );
258
259 let CompileUnit {
260 package,
261 ast,
262 errors,
263 ..
264 } = compiled.0;
265
266 expect![[r#"
267 Package:
268 entry expression: Expr 8 [0-0] [Type Unit]: Call:
269 Expr 7 [24-28] [Type Unit]: Var: Item 1
270 Expr 6 [28-30] [Type Unit]: Unit
271 Item 0 [0-40] (Public):
272 Namespace (Ident 5 [0-40] "test"): Item 1
273 Item 1 [0-40] (Internal):
274 Parent: 0
275 EntryPoint
276 Callable 0 [14-40] (operation):
277 name: Ident 1 [24-28] "Main"
278 input: Pat 2 [28-30] [Type Unit]: Unit
279 output: Unit
280 functors: empty set
281 body: SpecDecl 3 [14-40]: Impl:
282 Block 4 [38-40]: <empty>
283 adj: <none>
284 ctl: <none>
285 ctl-adj: <none>"#]]
286 .assert_eq(&package.to_string());
287 expect![[r#"
288 Package 0:
289 Namespace 1 [0-40] (Ident 2 [0-40] "test"):
290 Item 3 [0-40]:
291 Attr 4 [0-13] (Ident 5 [1-11] "EntryPoint"):
292 Expr 6 [11-13]: Unit
293 Callable 7 [14-40] (Operation):
294 name: Ident 8 [24-28] "Main"
295 input: Pat 9 [28-30]: Unit
296 output: Type 10 [33-37]: Path: Path 11 [33-37] (Ident 12 [33-37] "Unit")
297 body: Block: Block 13 [38-40]: <empty>"#]]
298 .assert_eq(&ast.package.to_string());
299 expect![[r"
300 []
301 "]]
302 .assert_debug_eq(&errors);
303}
304
305#[allow(clippy::too_many_lines)]
306#[test]
307fn entry_point_profile_in_project_causes_error() {
308 let program = mock_program();
309 // Inject a syntax error into one of the dependencies
310 let ProjectType::QSharp(mut package_graph_sources) = program.project_type else {
311 panic!("project should be a Q# project");
312 };
313 package_graph_sources
314 .root
315 .sources
316 .iter_mut()
317 .next()
318 .expect("expected at least one source in the mock program")
319 .1 = "@EntryPoint(Base) operation Main() : Unit { }".into();
320
321 let buildable_program =
322 super::prepare_package_store(TargetCapabilityFlags::default(), package_graph_sources);
323
324 expect![[r#"
325 [
326 WithSource {
327 sources: [
328 Source {
329 name: "test.qs",
330 contents: "@EntryPoint(Base) operation Main() : Unit { }",
331 offset: 0,
332 },
333 ],
334 error: EntryPointProfileInProject(
335 Span {
336 lo: 12,
337 hi: 16,
338 },
339 ),
340 },
341 ]
342 "#]]
343 .assert_debug_eq(&buildable_program.dependency_errors);
344}
345