about summary refs log tree commit diff
path: root/src/libsyntax_ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax_ext')
-rw-r--r--src/libsyntax_ext/lib.rs2
-rw-r--r--src/libsyntax_ext/test.rs10
-rw-r--r--src/libsyntax_ext/test_case.rs75
3 files changed, 85 insertions, 2 deletions
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index a9990cdeabf..e16f3b1ccb3 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -54,6 +54,7 @@ mod global_asm;
 mod log_syntax;
 mod trace_macros;
 mod test;
+mod test_case;
 
 pub mod proc_macro_registrar;
 
@@ -145,6 +146,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         assert: assert::expand_assert,
     }
 
+    register(Symbol::intern("test_case"), MultiModifier(Box::new(test_case::expand)));
 
     // format_args uses `unstable` things internally.
     register(Symbol::intern("format_args"),
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index d9d0f3d0a32..be3485cfa7c 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -135,8 +135,14 @@ pub fn expand_test_or_bench(
     };
 
     let mut test_const = cx.item(sp, item.ident.gensym(),
-        // #[test_case]
-        vec![cx.attribute(attr_sp, cx.meta_word(attr_sp, Symbol::intern("test_case")))],
+        vec![
+            // #[cfg(test)]
+            cx.attribute(attr_sp, cx.meta_list(attr_sp, Symbol::intern("cfg"), vec![
+                cx.meta_list_item_word(attr_sp, Symbol::intern("test"))
+            ])),
+            // #[rustc_test_marker]
+            cx.attribute(attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker")))
+        ],
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
             // test::TestDescAndFn {
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
new file mode 100644
index 00000000000..0128db7dd78
--- /dev/null
+++ b/src/libsyntax_ext/test_case.rs
@@ -0,0 +1,75 @@
+
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// #[test_case] is used by custom test authors to mark tests
+// When building for test, it needs to make the item public and gensym the name
+// Otherwise, we'll omit the item. This behavior means that any item annotated
+// with #[test_case] is never addressable.
+//
+// We mark item with an inert attribute "rustc_test_marker" which the test generation
+// logic will pick up on.
+
+use syntax::ext::base::*;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::hygiene::{self, Mark, SyntaxContext};
+use syntax::ast;
+use syntax::source_map::respan;
+use syntax::symbol::Symbol;
+use syntax_pos::{DUMMY_SP, Span};
+use syntax::source_map::{ExpnInfo, MacroAttribute};
+use syntax::feature_gate;
+
+pub fn expand(
+    ecx: &mut ExtCtxt,
+    attr_sp: Span,
+    _meta_item: &ast::MetaItem,
+    anno_item: Annotatable
+) -> Vec<Annotatable> {
+    if !ecx.ecfg.enable_custom_test_frameworks() {
+        feature_gate::emit_feature_err(&ecx.parse_sess,
+                                       "custom_test_frameworks",
+                                       attr_sp,
+                                       feature_gate::GateIssue::Language,
+                                       feature_gate::EXPLAIN_CUSTOM_TEST_FRAMEWORKS);
+
+        return vec![anno_item];
+    }
+
+    if !ecx.ecfg.should_test { return vec![]; }
+
+    let sp = {
+        let mark = Mark::fresh(Mark::root());
+        mark.set_expn_info(ExpnInfo {
+            call_site: DUMMY_SP,
+            def_site: None,
+            format: MacroAttribute(Symbol::intern("test_case")),
+            allow_internal_unstable: true,
+            allow_internal_unsafe: false,
+            local_inner_macros: false,
+            edition: hygiene::default_edition(),
+        });
+        attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
+    };
+
+    let mut item = anno_item.expect_item();
+
+    item = item.map(|mut item| {
+        item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+        item.ident = item.ident.gensym();
+        item.attrs.push(
+            ecx.attribute(sp,
+                ecx.meta_word(sp, Symbol::intern("rustc_test_marker")))
+        );
+        item
+    });
+
+    return vec![Annotatable::Item(item)]
+}