| """Voice flips, coordinated-verb splitting, and per-request structure rotation.""" |
|
|
| from __future__ import annotations |
|
|
| from app.engine import orchestrator |
| from app.engine.split import try_split_coordinated_verbs, try_split_long_sentence |
| from app.engine.variation import rotate |
| from app.engine.voice import active_to_passive, passive_to_active |
|
|
|
|
| def test_passive_to_active_recovers_the_agent(): |
| text = ( |
| "Areas for improvement can be identified by businesses that actively " |
| "listen to customer feedback." |
| ) |
| assert passive_to_active(text) == ( |
| "Businesses that actively listen to customer feedback can identify " |
| "areas for improvement." |
| ) |
|
|
|
|
| def test_passive_to_active_keeps_perfect_and_past_tense(): |
| assert passive_to_active("The budget has been approved by the committee.") == ( |
| "The committee has approved the budget." |
| ) |
| assert passive_to_active("The report was reviewed by readers yesterday.") == ( |
| "Readers reviewed the report yesterday." |
| ) |
|
|
|
|
| def test_passive_to_active_needs_an_explicit_agent(): |
| assert passive_to_active("The window was broken.") is None |
|
|
|
|
| def test_passive_to_active_skips_negation_needing_do_support(): |
| |
| assert passive_to_active("Mistakes were not corrected by the editor.") is None |
|
|
|
|
| def test_active_to_passive_refuses_to_relocate_a_fronted_phrase(): |
| """Leftovers land after the agent, which would strip the opener's scope.""" |
| text = ( |
| "By consistently delivering high-quality service, organizations can " |
| "establish a strong reputation." |
| ) |
| assert active_to_passive(text) is None |
|
|
|
|
| def test_active_to_passive_refuses_to_strand_a_preverbal_adverb(): |
| assert active_to_passive( |
| "Organizations can also encourage positive recommendations." |
| ) is None |
| assert active_to_passive("Maria carefully submitted the final report.") is None |
|
|
|
|
| def test_active_to_passive_keeps_hyphenated_compounds_intact(): |
| result = active_to_passive("The team published the high-quality version last week.") |
| assert result == "The high-quality version was published by the team last week." |
|
|
|
|
| def test_active_and_passive_are_not_mutually_reachable(): |
| text = "Readers reviewed the report yesterday." |
| passive = active_to_passive(text) |
| assert passive is not None |
| assert passive_to_active(passive) is not None |
|
|
|
|
| def test_active_to_passive_refuses_misattached_coordinate_tails(): |
| """spaCy may hang list verbs as advcl; rebuilding would strand them.""" |
| text = ( |
| "Customers appreciate companies that respond quickly to their questions, " |
| "resolve issues efficiently, and treat them with respect." |
| ) |
| assert active_to_passive(text) is None |
|
|
|
|
| def test_unfront_opener_moves_prepositional_prefix(): |
| from app.engine.templates import try_unfront_opener |
|
|
| assert try_unfront_opener( |
| "For the success of any business, supplying excellent customer service " |
| "is vital." |
| ) == ( |
| "Supplying excellent customer service is vital for the success of any " |
| "business." |
| ) |
| assert try_unfront_opener( |
| "By consistently delivering high-quality service, organizations can " |
| "establish a strong reputation." |
| ) == ( |
| "Organizations can establish a strong reputation by consistently " |
| "delivering high-quality service." |
| ) |
| |
| assert try_unfront_opener( |
| "However, the committee approved the budget today." |
| ) is None |
|
|
|
|
| def test_coordinated_split_repeats_subject_instead_of_stranding_a_verb(): |
| text = ( |
| "By consistently delivering high-quality service, organizations can " |
| "establish a strong reputation, gain customer retention, and encourage " |
| "positive word-of-mouth recommendations." |
| ) |
| assert try_split_coordinated_verbs(text) == ( |
| "By consistently delivering high-quality service, organizations can " |
| "establish a strong reputation and gain customer retention. " |
| "Organizations can also encourage positive word-of-mouth recommendations." |
| ) |
|
|
|
|
| def test_coordinated_split_refuses_ambiguous_relative_clause(): |
| """The verb list belongs to "organizations", not to "Customers".""" |
| text = ( |
| "Customers appreciate organizations that respond promptly to their " |
| "questions, resolve issues efficiently, and treat them with respect." |
| ) |
| assert try_split_coordinated_verbs(text) is None |
|
|
|
|
| def test_plain_split_refuses_to_strand_a_bare_verb_phrase(): |
| text = ( |
| "By consistently delivering high-quality service, organizations can " |
| "establish a strong reputation, gain customer retention, and encourage " |
| "positive word-of-mouth recommendations." |
| ) |
| result = try_split_long_sentence(text) |
| assert result is None or "Encourage positive" not in result |
|
|
|
|
| def test_rotation_keeps_weak_options_behind_the_band(): |
| options = [("best", 0.90), ("near", 0.78), ("weak", 0.40)] |
| for seed in range(6): |
| ordered = rotate( |
| options, seed=seed, confidence_of=lambda item: item[1] |
| ) |
| assert ordered[-1] == ("weak", 0.40) |
| assert set(ordered) == set(options) |
|
|
|
|
| def test_rotation_without_seed_preserves_order(): |
| options = [("a", 0.9), ("b", 0.8)] |
| assert rotate(options, seed=None, confidence_of=lambda i: i[1]) == options |
|
|
|
|
| def test_same_sentence_takes_different_structures(structural_variation): |
| text = "The teacher graded the papers carefully yesterday." |
| outputs = { |
| orchestrator.rewrite_document( |
| text, |
| use_lexical_refinement=False, |
| use_paraphrase=False, |
| use_minilm_safety=False, |
| ).text |
| for _ in range(12) |
| } |
| assert len(outputs) > 1 |
| for candidate in outputs: |
| assert "teacher" in candidate |
| assert "papers" in candidate |
|
|
|
|
| def test_directional_place_is_not_fronted(): |
| """"To school, Ram went" is marked; locative fronting stays available.""" |
| outputs = { |
| orchestrator.rewrite_document( |
| "Ram went to school yesterday happily.", |
| use_lexical_refinement=False, |
| use_paraphrase=False, |
| use_minilm_safety=False, |
| variation_seed=seed, |
| ).text |
| for seed in range(1, 10) |
| } |
| for candidate in outputs: |
| assert not candidate.lower().startswith("to school,") |
|
|