use std::{fs, path::PathBuf}; use rottlib::lexer::{Keyword, Token, TokenizedFile}; /// Returns the path to a fixture file in `tests/fixtures/`. fn fixture_file_path(name: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("fixtures") .join(name) } /// Loads a fixture source file as UTF-8 text. fn read_fixture_source(name: &str) -> String { fs::read_to_string(fixture_file_path(name)) .unwrap_or_else(|e| panic!("failed to read fixture {name}: {e}")) } /// Returns the token at the given token index on a physical line. /// /// Here `line` is 1-based, to match human line numbers in fixture files. /// `token_index` is 0-based within `TokenizedFile::line_tokens`. fn token_on_line(file: &TokenizedFile<'_>, line: usize, token_index: usize) -> Option { file.line_tokens(line - 1) .nth(token_index) .map(|(_, token_data)| token_data.token) } /// Returns reconstructed visible text for a physical line. /// /// Here `line` is 1-based, to match human line numbers in fixture files. fn line_text(file: &TokenizedFile<'_>, line: usize) -> Option { file.line_text(line - 1) } #[test] fn command_api_fixture_queries() { let source = read_fixture_source("CommandAPI.uc"); let file = TokenizedFile::tokenize(&source); assert_eq!(file.line_count(), 1578); assert_eq!( line_text(&file, 704).as_deref(), Some( "public final function CommandConfigInfo ResolveCommandForUserID(BaseText itemName, UserID id) {" ) ); assert_eq!( line_text(&file, 806).as_deref(), Some(" _.memory.Free(wrapper);") ); assert_eq!( line_text(&file, 1274).as_deref(), Some("/// Method must be called after [`Voting`] with a given name is added.") ); assert_eq!( line_text(&file, 14).as_deref(), Some(" * Acedia is distributed in the hope that it will be useful,") ); let token = token_on_line(&file, 22, 0).unwrap(); assert_eq!(token, Token::Keyword(Keyword::Class)); let token = token_on_line(&file, 1577, 0).unwrap(); assert_eq!(token, Token::Keyword(Keyword::DefaultProperties)); let token = token_on_line(&file, 649, 4).unwrap(); assert_eq!(token, Token::Whitespace); } #[test] fn dbrecord_fixture_queries() { let source = read_fixture_source("DBRecord.uc"); let file = TokenizedFile::tokenize(&source); assert_eq!(file.line_count(), 1199); assert_eq!( line_text(&file, 149).as_deref(), Some(" * However, JSON pointers are not convenient or efficient enough for that,") ); assert_eq!( line_text(&file, 787).as_deref(), Some(" * 3. 'number' -> either `IntBox` or `FloatBox`, depending on") ); assert_eq!( line_text(&file, 1023).as_deref(), Some(" bool makeMutable)") ); assert_eq!( line_text(&file, 29).as_deref(), Some(" config(AcediaDB);") ); let token = token_on_line(&file, 565, 0).unwrap(); assert_eq!(token, Token::BlockComment); let token = token_on_line(&file, 467, 10).unwrap(); assert_eq!(token, Token::Identifier); let token = token_on_line(&file, 467, 9).unwrap(); assert_eq!(token, Token::LeftParenthesis); } #[test] fn kvehicle_fixture_queries() { let source = read_fixture_source("KVehicle.uc"); let file = TokenizedFile::tokenize(&source); assert_eq!(file.line_count(), 326); assert_eq!( line_text(&file, 12).as_deref(), Some(" virtual void setPhysics(BYTE NewPhysics, AActor *NewFloor, FVector NewFloorV);") ); assert_eq!( line_text(&file, 127).as_deref(), Some(" pc.myHUD.bCrosshairShow = pc.myHUD.default.bCrosshairShow;") ); assert_eq!( line_text(&file, 264).as_deref(), Some(" //////////////////////////////////////////////////////") ); assert_eq!( line_text(&file, 299).as_deref(), Some(" ExitPositions(0)=(X=0,Y=0,Z=0)") ); let token = token_on_line(&file, 17, 0).unwrap(); assert_eq!(token, Token::Newline); let token = token_on_line(&file, 20, 7).unwrap(); assert_eq!(token, Token::Less); let token = token_on_line(&file, 246, 2).unwrap(); assert_eq!(token, Token::Increment); }