2014-10-30 2 views
5

Piszę kod Rust, który manipuluje surowymi wskazówkami. Te surowe wskaźniki są następnie eksponowane na użytkowników za pomocą struktur używających ContravariantLifetime do wiązania czasu trwania struktury z moim obiektem.Czy mogę pisać testy dotyczące nieprawidłowych wcieleń?

Chciałbym móc pisać testy, które potwierdzą, że struktury skierowane do użytkownika nie mogą żyć dłużej niż mój obiekt. Mam kod jak poniżej:

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

To nie kompiluje, co jest dokładnie to, co chcę. Chciałbym jednak mieć zautomatyzowane sprawdzenie, czy to zachowanie jest prawdziwe, nawet po jakimkolwiek refaktoryzacji, którą wykonuję dla kodu.

W tej chwili najlepszym pomysłem jest napisanie jednorazowych plików Rust za pomocą tego kodu i wykonanie skryptów bashowych, aby spróbować je skompilować i wyszukać konkretne komunikaty o błędach, co wydaje się dość hackowskie.

+4

Niestety, nie ma natywnej obsługi testów niepowodzeń kompilacji. rustc ma infrastrukturę do osiągnięcia tego celu ('src/test/compile-fail' i in.), ale jest niestandardowy i nie jest ogólnie dostępny. –

+0

@ChrisMorgan: Czy wierzysz, że zainteresuje się społecznością za wspieranie tego rodzaju testów? Rust ma naprawdę ewoluowany system typów pozwalający na egzekwowanie wielu kontroli i dobrze jest sprawdzić, czy kontrole są faktycznie egzekwowane. W przeszłości z C++ używałam specyficznych testów Clanga (flaga '' -verify' + specyficzne komentarze Clanga) dla tego rodzaju rzeczy; jest dość zaawansowany. –

+0

@MatthieuM .: Wiem, że chciałbym, aby podczas projektowania biblioteki testowałem sprawdzanie, czy dany kod się nie kompiluje. –

Odpowiedz

1

Projekt Rust ma specjalny zestaw testów zwanych testami "kompiluj awarie", które wykonują dokładnie to, czego oczekujesz.

compiletest crate jest wydobycie tego pomysłu, który umożliwia innych bibliotek zrobić to samo:

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

Jednym z pomysłów, które dostaje w połowie drogi jest użycie „cechy” ładunek jest.

Określ testy z flagą cecha:

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

dodać do Cargo.toml:

[features] 

compile_failure = [] 

i uruchomić testy jak

cargo test --features compile_failure 

Oczywistą rzeczą jest to brakujące z automatyczne sprawdzenie "czy to była właściwa porażka". Jeśli nic więcej, to pozwala mi mieć testy, które są pół-żywe w mojej bazie kodu.

-2

Możesz opisać test, który prawdopodobnie zakończy się niepowodzeniem.

#[should_fail] 

Jako taki można napisać test, który próbuje złamać czas życia, który powinien mieć, a tym samym niepowodzenie, co w rzeczywistości byłoby przepustką.

Dla przykładu test „indeksu poza granice” patrz niżej (wyciągnięty z Rust guides)

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

wierzę, że w tym przykładzie będzie to błąd kompilacji, więc byłoby stać się rozumieć swoje skompilować błąd naruszenia na całe życie zostanie również złapany przez to.

+0

'# [should_fail]' odnosi się do błędów w czasie wykonywania (obecnie nazywanych "paniką"), a nie do błędów kompilacji. –

+0

Być może musimy naciskać na '# [should_fail_compile]' (półpoważny) – thecoshman