1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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)]
}