mod common;
use common::{fixture, ENGLISH_TEXT, GERMAN_TEXT};
use tokenx::{estimate_token_count, estimate_token_count_with, TokenEstimationOptions};
#[test]
fn short_english_text() {
assert_eq!(estimate_token_count(ENGLISH_TEXT), 11);
}
#[test]
fn german_text_with_umlauts() {
assert_eq!(estimate_token_count(GERMAN_TEXT), 49);
}
#[test]
fn fixtures_are_byte_for_byte() {
let cases: &[(&str, usize, usize)] = &[
("pg5200.txt", 142_082, 140_555),
("pg22367.txt", 146_052, 143_340),
("pg7337.txt", 41_567, 27_531),
("pg1982.txt", 38_514, 26_400),
];
for (name, bytes, code_points) in cases {
let text = fixture(name);
assert_eq!(text.len(), *bytes, "byte length of {name}");
assert_eq!(text.chars().count(), *code_points, "code points of {name}");
}
}
#[test]
fn english_ebook() {
assert_eq!(estimate_token_count(&fixture("pg5200.txt")), 32_323);
}
#[test]
fn german_ebook() {
assert_eq!(estimate_token_count(&fixture("pg22367.txt")), 33_968);
}
#[test]
fn chinese_ebook() {
assert_eq!(estimate_token_count(&fixture("pg7337.txt")), 11_425);
}
#[test]
fn japanese_ebook() {
assert_eq!(estimate_token_count(&fixture("pg1982.txt")), 10_533);
}
#[test]
fn empty_input_is_zero() {
assert_eq!(estimate_token_count(""), 0);
}
#[test]
fn plain_number_stays_one_token() {
assert_eq!(estimate_token_count("12345"), 1);
}
#[test]
fn decimal_number_stays_one_token() {
assert_eq!(estimate_token_count("3.14"), 1);
}
#[test]
fn grouped_decimal_number_stays_one_token() {
assert_eq!(estimate_token_count("1,000.50"), 1);
}
#[test]
fn embedded_numeric_separators_keep_existing_counts() {
assert_eq!(estimate_token_count("abc1,000def"), 3);
assert_eq!(estimate_token_count("abc1,000"), 3);
assert_eq!(estimate_token_count("1,000def"), 3);
}
#[test]
fn failed_long_numeric_candidate_keeps_existing_count() {
let mut input = String::from("1");
for _ in 0..16_000 {
input.push_str(",1");
}
input.push('x');
assert_eq!(estimate_token_count(&input), 32_001);
}
#[test]
fn mixed_content_not_one_to_one() {
let url = "https://example.com/path/to/resource";
assert!((estimate_token_count(url) as usize) < url.chars().count() / 2);
assert_eq!(estimate_token_count(url), 13);
}
#[test]
fn ecmascript_whitespace_set() {
assert_eq!(estimate_token_count("\u{FEFF}"), 0);
assert_eq!(estimate_token_count("\u{FEFF}\u{FEFF}"), 0);
assert_eq!(estimate_token_count("ab\u{FEFF}cd"), 2);
assert_eq!(estimate_token_count("\u{0085}"), 1);
assert_eq!(estimate_token_count("ab\u{0085}cd"), 1);
}
#[test]
fn mid_text_bom_splits_like_javascript() {
assert_eq!(estimate_token_count("word\u{FEFF}word"), 2);
assert_eq!(estimate_token_count("longword\u{FEFF}x"), 3);
}
#[test]
fn custom_chars_per_token_increases_count() {
let default_count = estimate_token_count("Hello world");
let opts = TokenEstimationOptions {
default_chars_per_token: Some(4.0),
..Default::default()
};
let custom = estimate_token_count_with("Hello world", &opts);
assert!(custom > default_count);
assert_eq!(default_count, 2);
assert_eq!(custom, 4);
}