summaryrefslogtreecommitdiff
path: root/test/test_lang.ml
blob: c9b7f1a797273a7ef68dbb7268cae63e085e7296 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
module L = Colitur_naming.Lang

let ok = function Ok x -> x | Error e -> Alcotest.failf "parse: %s" e

let sample =
  "[meta]\n\
   lang = xx\n\
   fallback = la\n\
   [celebration]\n\
   ef-lent-3-monday = Feria II hebdomadae III Quadragesimae\n\
   francis-de-sales = S. Francisci Salesii\n\
   [weekday]\n\
   sunday = Dominica\n\
   monday = Feria II\n\
   [month]\n\
   1 = Ianuarius\n\
   [month_abbr]\n\
   1 = Ian\n\
   [season]\n\
   lent = Quadragesima\n\
   [rank]\n\
   class-1 = I classis\n\
   [colour]\n\
   white = albus\n\
   [term]\n\
   epistle = Epistola\n"

let test_meta () =
  let t = ok (L.of_string sample) in
  Alcotest.(check string) "code" "xx" (L.code t);
  Alcotest.(check (option string)) "fallback" (Some "la") (L.fallback_code t)

let test_lookups () =
  let t = ok (L.of_string sample) in
  Alcotest.(check string) "celebration" "Feria II hebdomadae III Quadragesimae"
    (L.celebration t "ef-lent-3-monday");
  Alcotest.(check string) "weekday 0 is Sunday" "Dominica" (L.weekday t 0);
  Alcotest.(check string) "month 1" "Ianuarius" (L.month t 1);
  Alcotest.(check string) "month_abbr 1" "Ian" (L.month_abbr t 1);
  Alcotest.(check string) "season" "Quadragesima" (L.season t "lent");
  Alcotest.(check string) "rank" "I classis" (L.rank t "class-1");
  Alcotest.(check string) "colour" "albus" (L.colour t "white");
  Alcotest.(check string) "term" "Epistola" (L.term t "epistle")

(* THE load-bearing property: a missing key degrades to the key itself, never to
   empty. A partial translation must be usable from its first line, and an
   untranslated day must still say something a reader can act on. *)
let test_missing_degrades_to_key () =
  let t = ok (L.of_string sample) in
  Alcotest.(check string) "unknown celebration" "ef-advent-1-monday"
    (L.celebration t "ef-advent-1-monday");
  Alcotest.(check string) "unknown colour" "rose" (L.colour t "rose");
  Alcotest.(check string) "unknown term" "gospel" (L.term t "gospel")

let test_fallback_chain () =
  let base = ok (L.of_string "[meta]\nlang = la\n[celebration]\na = ALPHA\nb = BETA\n") in
  let over = ok (L.of_string "[meta]\nlang = xx\nfallback = la\n[celebration]\nb = BETA-XX\n") in
  let t = L.with_fallback over base in
  Alcotest.(check string) "own key wins" "BETA-XX" (L.celebration t "b");
  Alcotest.(check string) "falls back" "ALPHA" (L.celebration t "a");
  Alcotest.(check string) "neither: the key" "c" (L.celebration t "c")

(* --raw must be a real identity table, not a special case threaded through every
   call site: one table the whole program can pass around. *)
let test_raw_is_identity () =
  Alcotest.(check string) "celebration" "ef-epiphany" (L.celebration L.raw "ef-epiphany");
  Alcotest.(check string) "colour" "white" (L.colour L.raw "white");
  Alcotest.(check string) "weekday" "0" (L.weekday L.raw 0)

let test_malformed_is_error_not_crash () =
  match L.of_string "[celebration\nbroken" with
  | Error _ -> ()
  | Ok _ -> Alcotest.fail "a malformed language file must be an Error, never accepted"

let test_missing_meta_lang_is_error () =
  match L.of_string "[celebration]\na = B\n" with
  | Error _ -> ()
  | Ok _ -> Alcotest.fail "a language file with no [meta] lang must be an Error"

(* F1 regression: a hand-edited language file WILL grow duplicate [section]
   headers as contributors append entries over time (Tasks 3/4's 595-entry
   la.ini). Both blocks' keys must resolve -- silently dropping the second
   block is a data-loss footgun that surfaces as a false "missing name"
   report far from its real cause. *)
let test_duplicate_sections_all_merge () =
  let t =
    ok
      (L.of_string
         "[meta]\nlang = la\n[celebration]\na = ALPHA\n[weekday]\nsunday = Dominica\n\
          [celebration]\nb = BETA\n")
  in
  Alcotest.(check string) "first block's key" "ALPHA" (L.celebration t "a");
  Alcotest.(check string) "second block's key" "BETA" (L.celebration t "b")

let test_duplicate_key_across_sections_last_wins () =
  let t =
    ok
      (L.of_string
         "[meta]\nlang = la\n[celebration]\na = FIRST\n[celebration]\na = SECOND\n")
  in
  Alcotest.(check string) "later block's value wins" "SECOND" (L.celebration t "a")

let test_duplicate_key_within_section_last_wins () =
  let t = ok (L.of_string "[meta]\nlang = la\n[celebration]\na = FIRST\na = SECOND\n") in
  Alcotest.(check string) "later line's value wins" "SECOND" (L.celebration t "a")

let suite =
  ( "Lang",
    [ Alcotest.test_case "meta" `Quick test_meta;
      Alcotest.test_case "lookups" `Quick test_lookups;
      Alcotest.test_case "missing degrades to key" `Quick test_missing_degrades_to_key;
      Alcotest.test_case "fallback chain" `Quick test_fallback_chain;
      Alcotest.test_case "raw is identity" `Quick test_raw_is_identity;
      Alcotest.test_case "malformed is error" `Quick test_malformed_is_error_not_crash;
      Alcotest.test_case "missing meta lang is error" `Quick test_missing_meta_lang_is_error;
      Alcotest.test_case "duplicate sections all merge" `Quick test_duplicate_sections_all_merge;
      Alcotest.test_case "duplicate key across sections: last wins" `Quick
        test_duplicate_key_across_sections_last_wins;
      Alcotest.test_case "duplicate key within section: last wins" `Quick
        test_duplicate_key_within_section_last_wins ] )