microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/compiler/qsc_frontend/src/compile/preprocess/tests.rs

238lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::compile::preprocess::RemoveCircuitSpans;
5use crate::compile::{SourceMap, parse_all};
6use qsc_ast::ast::{
7 Attr, CallableBody, CallableDecl, Expr, ExprKind, Ident, NodeId, Path, PathKind,
8};
9use qsc_ast::ast::{ItemKind, Package, TopLevelNode};
10use qsc_ast::mut_visit::MutVisitor;
11use qsc_data_structures::language_features::LanguageFeatures;
12use qsc_data_structures::span::Span;
13use std::sync::Arc;
14
15use crate::compile::{TargetCapabilityFlags, preprocess::matches_config};
16
17fn named_attr(name: &str) -> Attr {
18 Attr {
19 name: Box::new(Ident {
20 name: name.into(),
21 span: Span::default(),
22 id: NodeId::default(),
23 }),
24 arg: Box::new(Expr {
25 id: NodeId::default(),
26 span: Span::default(),
27 kind: Box::new(ExprKind::Tuple(Box::new([]))),
28 }),
29 span: Span::default(),
30 id: NodeId::default(),
31 }
32}
33
34fn name_value_attr(name: &str, value: &str) -> Attr {
35 Attr {
36 name: Box::new(Ident {
37 name: name.into(),
38 span: Span::default(),
39 id: NodeId::default(),
40 }),
41 arg: Box::new(Expr {
42 id: NodeId::default(),
43 span: Span::default(),
44 kind: Box::new(ExprKind::Paren(Box::new(Expr {
45 id: NodeId::default(),
46 span: Span::default(),
47 kind: Box::new(ExprKind::Path(PathKind::Ok(Box::new(Path {
48 id: NodeId::default(),
49 span: Span::default(),
50 segments: None,
51 name: Box::new(Ident {
52 name: value.into(),
53 span: Span::default(),
54 id: NodeId::default(),
55 }),
56 })))),
57 }))),
58 }),
59 span: Span::default(),
60 id: NodeId::default(),
61 }
62}
63
64fn prepare_ast_for_circuit_tests() -> Package {
65 let circuit_source = (
66 Arc::from("circuit.qsc"),
67 Arc::from("namespace CircuitTest { operation Circuit(qs : Qubit[]) : Unit { X(qs[0]); } }"),
68 );
69 let qsharp_source = (
70 Arc::from("test.qs"),
71 Arc::from("namespace Test { operation Main(qs : Qubit[]) : Unit { X(qs[0]); } }"),
72 );
73 let sources = SourceMap::new([circuit_source, qsharp_source], None);
74 let (mut package, errs) = parse_all(&sources, LanguageFeatures::default());
75 assert!(errs.is_empty(), "{errs:?}");
76 let mut visitor = RemoveCircuitSpans::new(&sources);
77 visitor.visit_package(&mut package);
78 package
79}
80
81/// Helper to find a callable declaration by name in a package AST.
82fn find_callable<'a>(package: &'a Package, name: &str) -> &'a CallableDecl {
83 package
84 .nodes
85 .iter()
86 .find_map(|node| {
87 if let TopLevelNode::Namespace(ns) = node {
88 ns.items.iter().find_map(|item| {
89 if let ItemKind::Callable(decl) = item.kind.as_ref() {
90 if decl.name.name.as_ref() == name {
91 Some(decl.as_ref())
92 } else {
93 None
94 }
95 } else {
96 None
97 }
98 })
99 } else {
100 None
101 }
102 })
103 .unwrap_or_else(|| panic!("{name} callable not found"))
104}
105
106#[test]
107fn no_attrs_matches() {
108 assert!(matches_config(&[], TargetCapabilityFlags::empty()));
109}
110
111#[test]
112fn unknown_attrs_matches() {
113 assert!(matches_config(
114 &[Box::new(named_attr("unknown"))],
115 TargetCapabilityFlags::empty()
116 ));
117}
118
119#[test]
120fn none_attrs_matches_empty() {
121 assert!(matches_config(
122 &[Box::new(name_value_attr("Config", "Base"))],
123 TargetCapabilityFlags::empty()
124 ));
125}
126
127#[test]
128fn none_attrs_does_not_match_all() {
129 assert!(!matches_config(
130 &[Box::new(name_value_attr("Config", "Base"))],
131 TargetCapabilityFlags::all()
132 ));
133}
134
135#[test]
136fn none_attrs_does_not_match_adaptive() {
137 assert!(!matches_config(
138 &[Box::new(name_value_attr("Config", "Base"))],
139 TargetCapabilityFlags::Adaptive
140 ));
141}
142
143#[test]
144fn adaptive_attrs_does_not_match_empty() {
145 assert!(!matches_config(
146 &[Box::new(name_value_attr("Config", "Adaptive"))],
147 TargetCapabilityFlags::empty()
148 ));
149}
150
151#[test]
152fn integercomputations_attrs_does_not_match_empty() {
153 assert!(!matches_config(
154 &[Box::new(name_value_attr("Config", "IntegerComputations"))],
155 TargetCapabilityFlags::empty()
156 ));
157}
158
159#[test]
160fn floatingpointcomputations_attrs_does_not_match_empty() {
161 assert!(!matches_config(
162 &[Box::new(name_value_attr(
163 "Config",
164 "FloatingPointComputations"
165 ))],
166 TargetCapabilityFlags::empty()
167 ));
168}
169
170#[test]
171fn unrestricted_attrs_does_not_match_empty() {
172 assert!(!matches_config(
173 &[Box::new(name_value_attr("Config", "Unrestricted"))],
174 TargetCapabilityFlags::empty()
175 ));
176}
177
178#[test]
179fn unrestricted_attrs_matches_all() {
180 assert!(matches_config(
181 &[Box::new(name_value_attr("Config", "Unrestricted"))],
182 TargetCapabilityFlags::all()
183 ));
184}
185
186#[test]
187fn remove_circuit_spans_clears_stmt_spans_in_qsc_files() {
188 let ast = prepare_ast_for_circuit_tests();
189 let circuit_callable = find_callable(&ast, "Circuit");
190
191 // Assert the callable declaration has a non-default span
192 assert_ne!(
193 circuit_callable.span,
194 Span::default(),
195 "Callable span should not be default"
196 );
197
198 // Assert that the body is a block and all statement spans inside the callable are cleared
199 match circuit_callable.body.as_ref() {
200 CallableBody::Block(block) => {
201 for stmt in &block.stmts {
202 assert_eq!(
203 stmt.span,
204 Span::default(),
205 "Statement span inside Circuit should be cleared"
206 );
207 }
208 }
209 CallableBody::Specs(_) => panic!("Expected Circuit body to be a block"),
210 }
211}
212
213#[test]
214fn remove_circuit_spans_does_not_clear_spans_outside_qsc_files() {
215 let ast = prepare_ast_for_circuit_tests();
216 let main_callable = find_callable(&ast, "Main");
217
218 // Assert the callable declaration has a non-default span
219 assert_ne!(
220 main_callable.span,
221 Span::default(),
222 "Callable span should not be default"
223 );
224
225 // Assert that the body is a block and all statement spans inside the callable are NOT cleared
226 match main_callable.body.as_ref() {
227 CallableBody::Block(block) => {
228 for stmt in &block.stmts {
229 assert_ne!(
230 stmt.span,
231 Span::default(),
232 "Statement span inside Main should NOT be cleared"
233 );
234 }
235 }
236 CallableBody::Specs(_) => panic!("Expected Main body to be a block"),
237 }
238}
239