# How Unit Tests in Tests/TestConversionEngine.mm Verify the Conversion Engine Logic

> Understand how unit tests in Tests/TestConversionEngine.mm verify conversion logic. Learn how assertions validate data loading, ranking, encoding, and spell-checking.

- Repository: [dongyuwei/hallelujahim](https://github.com/dongyuwei/hallelujahim)
- Tags: how-to-guide
- Published: 2026-02-28

---

**The unit tests in `Tests/TestConversionEngine.mm` validate every public method of the `ConversionEngine` class, ensuring correct data loading, MARISA Trie prefix search, frequency-based ranking, Phonex encoding, translation lookup, and spell-checking integration through hard-coded assertions against known dictionary entries.**

The `hallelujahim` input method relies on the `ConversionEngine` class—implemented in `src/ConversionEngine.mm`—to power its predictive text, translation, and spell-checking features. The **unit tests in Tests/TestConversionEngine.mm** serve as the comprehensive validation suite, asserting that lexical data loads correctly from JSON sources and that search, ranking, and encoding algorithms return expected results for specific word queries like `"test"` and `"courage"`.

## Testing Data Loading and JSON Deserialization

The validation begins with ensuring the engine correctly deserializes its lexical database. The `testWordsWithFrequencyAndTranslation` method forces asynchronous data loading by accessing `self.engine.wordsWithFrequencyAndTranslation` and asserts that the JSON dictionary contains exactly **140,402 entries**. It further validates that a known word entry, `"test"`, contains the expected frequency value and translation array, confirming that `loadPreparedData` in `src/ConversionEngine.mm` (lines 27-36) correctly parses the [`dictionary/words_with_frequency_and_translation_and_ipa.json`](https://github.com/dongyuwei/hallelujahim/blob/main/dictionary/words_with_frequency_and_translation_and_ipa.json) file using the internal `deserializeJSON` method.

## Validating MARISA Trie Prefix Search

Predictive search functionality is verified through `testWordsStartsWith`, which exercises the `wordsStartsWith:` method (lines 75-86 in `src/ConversionEngine.mm`). This test checks that a query for the prefix `"test"` returns exactly **95 candidates** using the native C++ `marisa::Trie` implementation. The assertions confirm that the first results include expected words like `"test"` and `"testing"`, validating that the trie structure correctly indexes the dictionary for fast prefix retrieval.

## Verifying Frequency-Based Ranking

Two test methods ensure the sorting algorithm prioritizes common words. The `testSortWordsByFrequency` method confirms that after retrieving candidates, `sortWordsByFrequency:` (lines 89-103) reorders them by descending frequency, with the top-10 list matching expected high-frequency words. The `testSortWordsByFrequencyFromLargeNumberOfCandidates` test specifically validates behavior with large candidate sets—querying the prefix `"in"` returns over **50,000 words** and asserts that the highest-frequency result is the word `"in"` itself, ensuring performance does not degrade with scale.

## Testing Phonex Encoding via JavaScriptCore

Fuzzy phonetic matching is validated in `testPhonexEncode`, which exercises the `phonexEncode:` wrapper method (lines 107-108). The test verifies that the embedded [`phonex.js`](https://github.com/dongyuwei/hallelujahim/blob/main/phonex.js) script, executed within a `JSContext` (lines 66-73), encodes words consistently. Specific assertions check that similar-sounding words like `"courage"` and `"cerrage"` map to the same Phonex code, and that `"test"` encodes to `"T23"`, confirming the JavaScript-based phonetic algorithm integrates correctly with the Objective-C runtime.

## Translation, IPA, and Annotation Accuracy

The test suite validates dictionary lookups and string construction through several focused tests.

**`testGetTranslations`** calls `getTranslations:` for the word `"test"` and validates the exact strings `"n. 考验；试验；测试"` and `"vt. 试验；测试；接受测验"` appear in the returned array from the lexical data.

**`testGetPhoneticSymbolOfWord`** asserts that `getPhoneticSymbolOfWord:` returns the correct IPA notation `"tɛst"` for the input `"test"`.

**`testGetAnnotation`** and **`testGetAnnotationOfUpperCaseWord`** verify that `getAnnotation:` (lines 123-139) correctly concatenates IPA symbols and translation definitions into a multi-line formatted string, while also confirming case-insensitive processing preserves output accuracy.

## Spell-Checking and Candidate Aggregation

Complex integration logic is tested through methods that combine multiple suggestion sources.

**`testGetSuggestionOfSpellChecker`** validates that `getSuggestionOfSpellChecker:` (lines 58-73) merges suggestions from macOS `NSSpellChecker` with Phonex-derived fuzzy matches. The test inputs misspellings like `"aosome"` and `"Ausome"`, asserting the returned array contains expected corrections including phonetically similar words.

**`testGetCandidates`** exercises the most complex public method, `getCandidates:` (lines 82-122), which aggregates user-defined substitutions, MARISA Trie results, spell-checker suggestions, and entries from [`dictionary/cedict.json`](https://github.com/dongyuwei/hallelujahim/blob/main/dictionary/cedict.json) for pinyin support. The test confirms the method returns exactly **50 candidates** (the enforced cap), deduplicates across sources, places the original input buffer at index 0, and correctly processes English prefixes (`"tes"`), phonetic approximations (`"awsome"`), and Chinese pinyin inputs (`"xihongshi"`, `"xhs"`).

**`testGetCandidatesWithUpperCaseInput`** specifically verifies that `getCandidates:` preserves original capitalization in the output list, ensuring the UI displays user-typed casing correctly.

## Example Usage Patterns

The following Objective-C snippets demonstrate the same API surface validated by the unit tests in `dongyuwei/hallelujahim`.

```objc
// Obtain the singleton ConversionEngine
ConversionEngine *engine = [ConversionEngine sharedEngine];

// 1. Prefix search via MARISA Trie (fast predictive lookup)
NSArray *candidates = [engine wordsStartsWith:@"tes"];   // → ["test", "testing", …]

// 2. Frequency-based ranking
NSArray *sorted = [engine sortWordsByFrequency:candidates]; // Highest frequency first

// 3. Phonex encoding for fuzzy matching
NSString *code = [engine phonexEncode:@"courage"];   // → "K63"

// 4. Translation and IPA retrieval
NSArray *trans = [engine getTranslations:@"test"];
NSString *ipa  = [engine getPhoneticSymbolOfWord:@"test"];   // → "tɛst"

// 5. Full annotation construction (IPA + definitions)
NSString *annotation = [engine getAnnotation:@"test"];
// Returns: "[tɛst]\nn. 考验；试验；测试\nvt. 试验；测试；接受测验"

// 6. Spell-checking with phonetic fallback
NSArray *suggestions = [engine getSuggestionOfSpellChecker:@"aosome"];
// → ["Amos", "assume", "awesome", "assumes"]

// 7. Complete candidate aggregation (includes pinyin support)
NSArray *fullCandidates = [engine getCandidates:@"xihongshi"];
// Returns up to 50 unique suggestions including "tomato" and related terms

```

These patterns mirror the assertions in `Tests/TestConversionEngine.mm`, demonstrating how the engine supports live word completion, tooltip annotations, and multilingual input processing.

## Summary

- **Data Loading**: Tests verify 140,402 JSON entries load correctly via `loadPreparedData` in `src/ConversionEngine.mm`.
- **Prefix Search**: MARISA Trie integration returns exact candidate counts (e.g., 95 results for `"test"`) through `wordsStartsWith:`.
- **Frequency Ranking**: `sortWordsByFrequency:` correctly orders 50,000+ candidates without performance degradation.
- **Phonetic Encoding**: JavaScriptCore-based `phonexEncode:` generates consistent codes for fuzzy matching using the embedded [`phonex.js`](https://github.com/dongyuwei/hallelujahim/blob/main/phonex.js) script.
- **Dictionary Lookups**: Translation and IPA methods return exact strings for known entries like `"test"` from [`words_with_frequency_and_translation_and_ipa.json`](https://github.com/dongyuwei/hallelujahim/blob/main/words_with_frequency_and_translation_and_ipa.json).
- **Integration**: `getCandidates:` caps results at 50 items while merging spell-checker, trie, substitution, and pinyin sources from [`cedict.json`](https://github.com/dongyuwei/hallelujahim/blob/main/cedict.json).

## Frequently Asked Questions

### What specific conversion logic does TestConversionEngine.mm validate?

The file validates the entire `ConversionEngine` public API, including JSON data deserialization in `loadPreparedData`, MARISA Trie prefix searches via `wordsStartsWith:`, frequency sorting with `sortWordsByFrequency:`, Phonex encoding through `phonexEncode:`, and complex candidate aggregation in `getCandidates:`. Each test method targets a specific engine capability with hard-coded expected values derived from the dictionary files.

### How do the tests verify the Phonex encoding algorithm?

The `testPhonexEncode` method checks that `phonexEncode:` returns consistent codes for phonetically similar words (e.g., `"courage"` and `"cerrage"` mapping to the same code) and validates specific outputs like `"test"` encoding to `"T23"`. This confirms the embedded [`phonex.js`](https://github.com/dongyuwei/hallelujahim/blob/main/phonex.js) script executes correctly within the `JSContext` initialized in `src/ConversionEngine.mm` (lines 66-73).

### Why does the test suite check for exactly 50 candidates in getCandidates:?

The `testGetCandidates` method asserts the 50-item limit because `getCandidates:` (lines 82-122 in `src/ConversionEngine.mm`) intentionally caps results to ensure UI responsiveness. The test verifies this limit is enforced while confirming that deduplication occurs across the four input sources: user substitutions, MARISA Trie matches, spell-checker suggestions, and pinyin dictionary entries.

### How does TestConversionEngine.mm handle case sensitivity testing?

The suite includes `testGetAnnotationOfUpperCaseWord` and `testGetCandidatesWithUpperCaseInput` to ensure `getAnnotation:` and `getCandidates:` process inputs case-insensitively while preserving the original capitalization in output strings. This validates that the engine normalizes search queries without destroying user-typed casing for display purposes.