Files
aventuriers-des-mots/tests/data/test_no_near_duplicate_sentences.gd
T
2026-10-12 10:45:31 +02:00

101 lines
3.8 KiB
GDScript

extends GutTest
## Deux phrases qui ne different que d'un mot (« Les petits chiens courent. »
## / « Les petits chiens jouent. ») donnent a l'enfant l'impression d'une
## redite. On compare les ensembles de mots : au-dela de 75 % de mots communs
## (phrases d'au moins 4 mots), les deux phrases sont jugees trop proches.
const EXERCISES_DIR := "res://data/exercises"
const DICTATIONS_DIR := "res://data/dictations"
const MAX_SIMILARITY := 0.75
const MIN_WORDS := 4
func test_no_two_sentences_are_nearly_identical() -> void:
var entries := _collect()
var close: Array[String] = []
for i in range(entries.size()):
for j in range(i + 1, entries.size()):
var a: Array = entries[i]["words"]
var b: Array = entries[j]["words"]
if a.size() < MIN_WORDS or b.size() < MIN_WORDS:
continue
var common := 0
for word: String in a:
if b.has(word):
common += 1
var similarity := float(common) / float(maxi(a.size(), b.size()))
if similarity >= MAX_SIMILARITY:
close.append(
(
"%s « %s » ~ %s « %s »"
% [
entries[i]["id"],
entries[i]["text"],
entries[j]["id"],
entries[j]["text"]
]
)
)
assert_eq(close.size(), 0, "Phrases trop proches :\n%s" % "\n".join(close))
assert_gt(entries.size(), 100)
func _collect() -> Array[Dictionary]:
var entries: Array[Dictionary] = []
for path in _json_files(EXERCISES_DIR):
var data := _read(path)
var sentence := ""
if data.get("type", "") == "multiple_choice":
var answers: Array = data["answers"]
sentence = str(data["question"]).replace(
"...", str(answers[int(data["correct_answer"])])
)
elif data.get("type", "") == "sentence_correction":
var words: Array[String] = []
for token: Dictionary in data["tokens"]:
words.append(token["text"] if token["correct"] else token["expected"])
sentence = " ".join(words)
if not sentence.is_empty():
entries.append({"id": data["id"], "text": sentence, "words": _words(sentence)})
for path in _json_files(DICTATIONS_DIR):
var data := _read(path)
var text: String = data["target_text"]
entries.append({"id": data["id"], "text": text, "words": _words(text)})
return entries
## Mots distincts, en minuscules, sans ponctuation.
func _words(sentence: String) -> Array[String]:
var cleaned := ""
for character in sentence.to_lower():
if character == "'" or character == " ":
cleaned += " "
elif character.to_upper() != character or "éèêàâîïôûùçœ".contains(character):
cleaned += character
else:
cleaned += " "
var result: Array[String] = []
for word in cleaned.split(" ", false):
if not result.has(word):
result.append(word)
return result
func _json_files(path: String) -> Array[String]:
var found: Array[String] = []
var dir := DirAccess.open(path)
if dir == null:
return found
for sub in dir.get_directories():
found.append_array(_json_files(path.path_join(sub)))
for file_name in dir.get_files():
if file_name.ends_with(".json"):
found.append(path.path_join(file_name))
return found
func _read(path: String) -> Dictionary:
var file := FileAccess.open(path, FileAccess.READ)
var parsed: Variant = JSON.parse_string(file.get_as_text())
return parsed if typeof(parsed) == TYPE_DICTIONARY else {}