2014-10-30 12 views
5

Sto scrivendo del codice Rust che manipola i puntatori grezzi. Questi puntatori grezzi vengono quindi esposti agli utenti attraverso strutture che utilizzano ContravariantLifetime per legare la durata della struttura al mio oggetto.Posso scrivere test per vite non valide?

Mi piacerebbe essere in grado di scrivere test che convalidino che le strutture rivolte all'utente non possono vivere più a lungo del mio oggetto. Ho codice come il seguente:

fn element_cannot_outlive_parts() { 
    let mut z = { 
     let p = Package::new(); 
     p.create() // returns an object that cannot live longer than p 
    }; 
} 

Questo non riesce a compilare, che è esattamente quello che voglio. Tuttavia, mi piacerebbe avere qualche controllo automatico che questo comportamento sia vero anche dopo qualsiasi refactoring che faccio al codice.

Al momento, la mia migliore idea è quella di scrivere file Rust unici con questo codice e di configurare gli script di bash per tentare di compilarli e cercare specifici messaggi di errore, il che sembra abbastanza pericoloso.

+4

Purtroppo, non è disponibile il supporto nativo per i test per la compilazione non riuscita. rugc stesso ha un'infrastruttura per raggiungere questo ('src/test/compile-fail' et al.), ma è personalizzato e non è generalmente disponibile. –

+0

@ChrisMorgan: Credi che ci sarebbe interesse per la comunità per supportare questo tipo di test? Rust ha un sistema di tipi molto evoluto che consente di imporre molti controlli e sembra opportuno verificare che i controlli siano effettivamente applicati. In passato, con C++, ho usato i test specifici di Clang (flag '-verify' + commenti specifici di Clang) per questo genere di cose; è abbastanza avanzato. –

+0

@MatthieuM .: So che mi piacerebbe che, durante la progettazione di una libreria, fossero eseguiti test per verificare che un determinato codice non venisse compilato. –

risposta

1

Il progetto Rust ha una serie speciale di test denominati "compile-fail" che fanno esattamente ciò che si desidera.

Il compiletest crate è un'estrazione di questa idea che permette altre librerie per fare la stessa cosa:

fn main() { 
    let x: (u64, bool) = (true, 42u64); 
    //~^ ERROR mismatched types 
    //~^^ ERROR mismatched types 
} 

Un'idea che viene a metà strada è quella di utilizzare "caratteristiche" del Cargo.

Specificare test con una bandiera caratteristica:

#[test] 
#[cfg(feature = "compile_failure")] 
fn bogus_test() {} 

aggiungere questo alla Cargo.toml:

[features] 

compile_failure = [] 

e test eseguiti come

cargo test --features compile_failure 

La cosa ovvia mancanti da questo è il controllo automatico di "è stato il giusto fallimento". Se non altro, questo mi permette di avere test che sono semi-viventi nella mia base di codice.

-2

È possibile annotare un test che si prevede di non riuscire.

#[should_fail] 

Come tale, si può scrivere un test che tenta di violare il tempo di vita dovrebbe avere, e quindi fallire, che sarebbe in realtà un passaggio.

Per un esempio di un test per 'indice fuori limite' vedi qui sotto (tirato dal Rust guides)

#[test] 
#[should_fail] 
fn test_out_of_bounds_failure() { 
    let v: &[int] = []; 
    v[0]; 
} 

Credo che questo esempio potrebbe essere un errore di compilazione, quindi sarebbe stare alla ragione la vostra anche questo errore di violazione della durata della compilazione.

+0

'# [dovrebbe_fail]' è per gli errori di runtime (ora chiamati "panic"), non per gli errori di compilazione. –

+0

Forse dovremmo premere per '# [should_fail_compile]' (semi-serio) – thecoshman

Problemi correlati