crosvm/sys_util/poll_token_derive/tests.rs
Zach Reizner 25c6bc137e sys_util: custom derive for PollToken
Using an enum implementing PollToken is the recommended way to use
PollContext, but writing the trait impls for each enum is mechanical yet
error prone. This is a perfect candidate for a custom derive, which
automates away the process using a simple derive attribute on an enum.

BUG=chromium:816692
TEST=cargo test -p sys_util

Change-Id: If21d0f94f9af4b4f6cef1f24c78fc36b50471053
Reviewed-on: https://chromium-review.googlesource.com/940865
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
2018-03-07 16:54:46 -08:00

257 lines
8.3 KiB
Rust

// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
mod tokenized {
use Tokenized;
use Tokenized::*;
#[test]
fn enum_() {
assert_eq!(Tokenized::from_str("enum"), Enum);
}
#[test]
fn visibility() {
assert_eq!(Tokenized::from_str("pub"), Visiblity);
assert_eq!(Tokenized::from_str("pub(crate)"), Visiblity);
assert_eq!(Tokenized::from_str("pub(my_module)"), Visiblity);
assert_eq!(Tokenized::from_str("pub( crate )"), Visiblity);
}
#[test]
fn ident() {
assert_eq!(Tokenized::from_str("Important"),
Ident("Important".to_owned()));
assert_eq!(Tokenized::from_str("hello,"), Ident("hello".to_owned()));
assert_eq!(Tokenized::from_str("world2"), Ident("world2".to_owned()));
assert_eq!(Tokenized::from_str("A,"), Ident("A".to_owned()));
}
#[test]
fn field_ident() {
assert_eq!(Tokenized::from_str("index:"),
FieldIdent("index".to_owned()));
assert_eq!(Tokenized::from_str("a:"), FieldIdent("a".to_owned()));
}
#[test]
fn ident_and_type() {
assert_eq!(Tokenized::from_str("a(u32)"),
IdentAndType("a".to_owned(), "u32".to_owned()));
assert_eq!(Tokenized::from_str("Socket(usize),"),
IdentAndType("Socket".to_owned(), "usize".to_owned()));
}
#[test]
fn open_brace() {
assert_eq!(Tokenized::from_str("{"), OpenBrace);
}
#[test]
fn close_brace() {
assert_eq!(Tokenized::from_str("}"), CloseBrace);
assert_eq!(Tokenized::from_str("},"), CloseBrace);
}
#[test]
#[should_panic]
fn empty() {
Tokenized::from_str("");
}
}
mod parse_state {
use {Tokenized, States, ParseState, EnumModel, EnumVariant, EnumVariantData};
use Tokenized::*;
fn parse_tokens(tokens: &[Tokenized]) -> EnumModel {
let mut state = ParseState::new();
for token in tokens {
state.handle_token(token.clone());
}
assert_eq!(state.current_state,
States::End,
"unexpected end after parsing source enum");
state.model
}
#[test]
fn empty_struct() {
let model = parse_tokens(&[Visiblity,
Enum,
Ident("Blarg".to_owned()),
OpenBrace,
CloseBrace]);
let expected = EnumModel {
name: "Blarg".to_string(),
variants: Vec::new(),
};
assert_eq!(model, expected);
}
#[test]
#[should_panic]
fn invalid_token() {
parse_tokens(&[Visiblity,
Enum,
Ident("Blarg".to_owned()),
OpenBrace,
CloseBrace,
CloseBrace]);
}
#[test]
fn only_unit_variants() {
let model = parse_tokens(&[Enum,
Ident("Foo".to_owned()),
OpenBrace,
Ident("A".to_owned()),
Ident("B".to_owned()),
Ident("C".to_owned()),
CloseBrace]);
let expected = EnumModel {
name: "Foo".to_string(),
variants: vec![EnumVariant {
name: "A".to_owned(),
data: None,
},
EnumVariant {
name: "B".to_owned(),
data: None,
},
EnumVariant {
name: "C".to_owned(),
data: None,
}],
};
assert_eq!(model, expected);
}
#[test]
fn unnamed_data() {
let model = parse_tokens(&[Enum,
Ident("Foo".to_owned()),
OpenBrace,
IdentAndType("A".to_owned(), "u32".to_owned()),
Ident("B".to_owned()),
IdentAndType("C".to_owned(), "usize".to_owned()),
CloseBrace]);
let expected = EnumModel {
name: "Foo".to_string(),
variants: vec![EnumVariant {
name: "A".to_owned(),
data: Some(EnumVariantData {
name: None,
type_: "u32".to_owned(),
}),
},
EnumVariant {
name: "B".to_owned(),
data: None,
},
EnumVariant {
name: "C".to_owned(),
data: Some(EnumVariantData {
name: None,
type_: "usize".to_owned(),
}),
}],
};
assert_eq!(model, expected);
}
#[test]
fn named_data() {
let model = parse_tokens(&[Enum,
Ident("Foo".to_owned()),
OpenBrace,
Ident("A".to_owned()),
OpenBrace,
FieldIdent("index".to_owned()),
Ident("u16".to_owned()),
CloseBrace,
CloseBrace]);
let expected = EnumModel {
name: "Foo".to_string(),
variants: vec![EnumVariant {
name: "A".to_owned(),
data: Some(EnumVariantData {
name: Some("index".to_owned()),
type_: "u16".to_owned(),
}),
}],
};
assert_eq!(model, expected);
}
}
mod enum_model {
use {EnumModel, EnumVariant};
#[test]
fn variant_bits() {
let mut model = EnumModel {
name: "Baz".to_string(),
variants: vec![EnumVariant {
name: "A".to_owned(),
data: None,
},
EnumVariant {
name: "B".to_owned(),
data: None,
},
EnumVariant {
name: "C".to_owned(),
data: None,
}],
};
assert_eq!(model.variant_bits(), 2);
for _ in 0..1021 {
model
.variants
.push(EnumVariant {
name: "Dynamic".to_owned(),
data: None,
});
}
assert_eq!(model.variant_bits(), 10);
model
.variants
.push(EnumVariant {
name: "OneMore".to_owned(),
data: None,
});
assert_eq!(model.variant_bits(), 11);
}
}
#[test]
fn poll_token_e2e() {
let input = "enum Token { A, B, C, D(usize), E { foobaz: u32 }, }";
let output = ::poll_token_inner(input);
let expected = "impl PollToken for Token {
fn as_raw_token(&self) -> u64 {
match *self {
Token::A => 0,
Token::B => 1,
Token::C => 2,
Token::D(data) => 3 | ((data as u64) << 3),
Token::E{ foobaz: data } => 4 | ((data as u64) << 3),
}
}
fn from_raw_token(data: u64) -> Self {
match data & 0x07 {
0 => Token::A,
1 => Token::B,
2 => Token::C,
3 => Token::D((data >> 3) as usize),
4 => Token::E{ foobaz: (data >> 3) as u32 },
_ => unreachable!()
}
}
}";
assert_eq!(output.as_str(), expected);
}