(* TEST
 expect;
*)

module M1 : sig
  type t = {f0 : unit * unit * unit * int * unit * unit * unit;
            f1 : unit * unit * unit * int * unit * unit * unit}
end = struct
  type t = {f0 : unit * unit * unit * float* unit * unit * unit;
            f1 : unit * unit * unit * string * unit * unit * unit}
end;;
[%%expect{|
Lines 4-7, characters 6-3:
4 | ......struct
5 |   type t = {f0 : unit * unit * unit * float* unit * unit * unit;
6 |             f1 : unit * unit * unit * string * unit * unit * unit}
7 | end..
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = {
             f0 : unit * unit * unit * float * unit * unit * unit;
             f1 : unit * unit * unit * string * unit * unit * unit;
           }
         end
       is not included in
         sig
           type t = {
             f0 : unit * unit * unit * int * unit * unit * unit;
             f1 : unit * unit * unit * int * unit * unit * unit;
           }
         end
       Type declarations do not match:
         type t = {
           f0 : unit * unit * unit * float * unit * unit * unit;
           f1 : unit * unit * unit * string * unit * unit * unit;
         }
       is not included in
         type t = {
           f0 : unit * unit * unit * int * unit * unit * unit;
           f1 : unit * unit * unit * int * unit * unit * unit;
         }
       1. Fields do not match:
         "f0 : unit * unit * unit * float * unit * unit * unit;"
       is not the same as:
         "f0 : unit * unit * unit * int * unit * unit * unit;"
       The type "unit * unit * unit * float * unit * unit * unit"
       is not equal to the type "unit * unit * unit * int * unit * unit * unit"
       Type "float" is not equal to type "int"
       2. Fields do not match:
         "f1 : unit * unit * unit * string * unit * unit * unit;"
       is not the same as:
         "f1 : unit * unit * unit * int * unit * unit * unit;"
       The type "unit * unit * unit * string * unit * unit * unit"
       is not equal to the type "unit * unit * unit * int * unit * unit * unit"
       Type "string" is not equal to type "int"
|}];;


module M2 : sig
  type t = {mutable f0 : unit * unit * unit * int * unit * unit * unit;
            f1 : unit * unit * unit * int * unit * unit * unit}
end = struct
  type t = {f0 : unit * unit * unit * float* unit * unit * unit;
            f1 : unit * unit * unit * string * unit * unit * unit}
end;;
[%%expect{|
Lines 4-7, characters 6-3:
4 | ......struct
5 |   type t = {f0 : unit * unit * unit * float* unit * unit * unit;
6 |             f1 : unit * unit * unit * string * unit * unit * unit}
7 | end..
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = {
             f0 : unit * unit * unit * float * unit * unit * unit;
             f1 : unit * unit * unit * string * unit * unit * unit;
           }
         end
       is not included in
         sig
           type t = {
             mutable f0 : unit * unit * unit * int * unit * unit * unit;
             f1 : unit * unit * unit * int * unit * unit * unit;
           }
         end
       Type declarations do not match:
         type t = {
           f0 : unit * unit * unit * float * unit * unit * unit;
           f1 : unit * unit * unit * string * unit * unit * unit;
         }
       is not included in
         type t = {
           mutable f0 : unit * unit * unit * int * unit * unit * unit;
           f1 : unit * unit * unit * int * unit * unit * unit;
         }
       1. Fields do not match:
         "f0 : unit * unit * unit * float * unit * unit * unit;"
       is not the same as:
         "mutable f0 : unit * unit * unit * int * unit * unit * unit;"
       The second is mutable and the first is not.
       2. Fields do not match:
         "f1 : unit * unit * unit * string * unit * unit * unit;"
       is not the same as:
         "f1 : unit * unit * unit * int * unit * unit * unit;"
       The type "unit * unit * unit * string * unit * unit * unit"
       is not equal to the type "unit * unit * unit * int * unit * unit * unit"
       Type "string" is not equal to type "int"
|}];;

module M3 : sig
  type t = {f0 : unit}
end = struct
  type t = {f1 : unit}
end;;
[%%expect{|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = {f1 : unit}
5 | end..
Error: Signature mismatch:
       Modules do not match:
         sig type t = { f1 : unit; } end
       is not included in
         sig type t = { f0 : unit; } end
       Type declarations do not match:
         type t = { f1 : unit; }
       is not included in
         type t = { f0 : unit; }
       Fields have different names, "f1" and "f0".
|}];;

module M4 : sig
  type t = {f0 : unit; f1 : unit}
end = struct
  type t = {f0 : unit}
end;;
[%%expect{|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = {f0 : unit}
5 | end..
Error: Signature mismatch:
       Modules do not match:
         sig type t = { f0 : unit; } end
       is not included in
         sig type t = { f0 : unit; f1 : unit; } end
       Type declarations do not match:
         type t = { f0 : unit; }
       is not included in
         type t = { f0 : unit; f1 : unit; }
       A field, "f1", is missing in the first declaration.
|}];;


(** Random additions and deletions of fields *)

module Addition : sig
  type t = {a : unit; b : unit; c : unit; d : unit}
end = struct
  type t = {a : unit; b : unit; beta : unit; c : unit; d: unit}
end
[%%expect {|
Lines 5-7, characters 6-3:
5 | ......struct
6 |   type t = {a : unit; b : unit; beta : unit; c : unit; d: unit}
7 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = { a : unit; b : unit; beta : unit; c : unit; d : unit; }
         end
       is not included in
         sig type t = { a : unit; b : unit; c : unit; d : unit; } end
       Type declarations do not match:
         type t = { a : unit; b : unit; beta : unit; c : unit; d : unit; }
       is not included in
         type t = { a : unit; b : unit; c : unit; d : unit; }
       An extra field, "beta", is provided in the first declaration.
|}]


module Deletion : sig
  type t = {a : unit; b : unit; c : unit; d : unit}
end = struct
  type t = {a : unit; c : unit; d : unit}
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = {a : unit; c : unit; d : unit}
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = { a : unit; c : unit; d : unit; } end
       is not included in
         sig type t = { a : unit; b : unit; c : unit; d : unit; } end
       Type declarations do not match:
         type t = { a : unit; c : unit; d : unit; }
       is not included in
         type t = { a : unit; b : unit; c : unit; d : unit; }
       A field, "b", is missing in the first declaration.
|}]


module Multi: sig
  type t = {
    a : unit;
    b : unit;
    c : unit;
    d : unit;
    e : unit;
    f : unit;
    g : unit
  }
end = struct
  type t = {
    a : unit;
    b : unit;
    beta: int;
    c : unit;
    d : unit;
    f : unit;
    g : unit;
    phi : unit;
  }
end

[%%expect {|
Lines 11-22, characters 6-3:
11 | ......struct
12 |   type t = {
13 |     a : unit;
14 |     b : unit;
15 |     beta: int;
...
19 |     g : unit;
20 |     phi : unit;
21 |   }
22 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = {
             a : unit;
             b : unit;
             beta : int;
             c : unit;
             d : unit;
             f : unit;
             g : unit;
             phi : unit;
           }
         end
       is not included in
         sig
           type t = {
             a : unit;
             b : unit;
             c : unit;
             d : unit;
             e : unit;
             f : unit;
             g : unit;
           }
         end
       Type declarations do not match:
         type t = {
           a : unit;
           b : unit;
           beta : int;
           c : unit;
           d : unit;
           f : unit;
           g : unit;
           phi : unit;
         }
       is not included in
         type t = {
           a : unit;
           b : unit;
           c : unit;
           d : unit;
           e : unit;
           f : unit;
           g : unit;
         }
       3. An extra field, "beta", is provided in the first declaration.
       5. A field, "e", is missing in the first declaration.
       8. An extra field, "phi", is provided in the first declaration.
|}]


(** Multiple errors *)

module M : sig
  type t = { a:int; e:int; c:int; d:int; b:int }
end = struct
  type t = { alpha:int; b:int; c:int; d:int; e:int }
end
[%%expect {|
Lines 5-7, characters 6-3:
5 | ......struct
6 |   type t = { alpha:int; b:int; c:int; d:int; e:int }
7 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = { alpha : int; b : int; c : int; d : int; e : int; }
         end
       is not included in
         sig type t = { a : int; e : int; c : int; d : int; b : int; } end
       Type declarations do not match:
         type t = { alpha : int; b : int; c : int; d : int; e : int; }
       is not included in
         type t = { a : int; e : int; c : int; d : int; b : int; }
       1. Fields have different names, "alpha" and "a".
       2<->5. Fields "b" and "e" have been swapped.
|}]


module M: sig
  type t = { a:int; b:int; c:int; d:int; e:int; f:float }
end =
struct
  type t = { b:int; c:int; d:int; e:int; a:int; f:int }
end
[%%expect {|
Lines 4-6, characters 0-3:
4 | struct
5 |   type t = { b:int; c:int; d:int; e:int; a:int; f:int }
6 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = { b : int; c : int; d : int; e : int; a : int; f : int; }
         end
       is not included in
         sig
           type t = {
             a : int;
             b : int;
             c : int;
             d : int;
             e : int;
             f : float;
           }
         end
       Type declarations do not match:
         type t = { b : int; c : int; d : int; e : int; a : int; f : int; }
       is not included in
         type t = { a : int; b : int; c : int; d : int; e : int; f : float; }
       1->5. Field "a" has been moved from position 1 to 5.
       6. Fields do not match:
         "f : int;"
       is not the same as:
         "f : float;"
       The type "int" is not equal to the type "float"
|}]

(** Existential types introduce equations that must be taken in account
    when diffing
*)


module Eq : sig
  type t = A: { a:'a; b:'b; x:'a } -> t
end = struct
  type t = A: { a:'a; b:'b; x:'x } -> t
end
[%%expect {|
Lines 8-10, characters 6-3:
 8 | ......struct
 9 |   type t = A: { a:'a; b:'b; x:'x } -> t
10 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = A : { a : 'a; b : 'b; x : 'x; } -> t end
       is not included in
         sig type t = A : { a : 'a; b : 'b; x : 'a; } -> t end
       Type declarations do not match:
         type t = A : { a : 'a; b : 'b; x : 'x; } -> t
       is not included in
         type t = A : { a : 'a; b : 'b; x : 'a; } -> t
       Constructors do not match:
         "A : { a : 'a; b : 'b; x : 'x; } -> t"
       is not the same as:
         "A : { a : 'a; b : 'b; x : 'a; } -> t"
       Fields do not match:
         "x : 'x;"
       is not the same as:
         "x : 'a;"
       The type "'x" is not equal to the type "'a"
|}]


module Not_a_swap: sig
  type t = A: { x:'a; a:'a; b:'b; y:'b} -> t
end = struct
  type t = A: { y:'a; a:'a; b:'b; x:'b} -> t
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = A: { y:'a; a:'a; b:'b; x:'b} -> t
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = A : { y : 'a; a : 'a; b : 'b; x : 'b; } -> t end
       is not included in
         sig type t = A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t end
       Type declarations do not match:
         type t = A : { y : 'a; a : 'a; b : 'b; x : 'b; } -> t
       is not included in
         type t = A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t
       Constructors do not match:
         "A : { y : 'a; a : 'a; b : 'b; x : 'b; } -> t"
       is not the same as:
         "A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t"
       1. Fields have different names, "y" and "x".
       4. Fields have different names, "x" and "y".
|}]

module Swap: sig
  type t = A: { x:'a; a:'a; b:'b; y:'b} -> t
end = struct
  type t = A: { y:'b; a:'a; b:'b; x:'a} -> t
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = A: { y:'b; a:'a; b:'b; x:'a} -> t
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = A : { y : 'b; a : 'a; b : 'b; x : 'a; } -> t end
       is not included in
         sig type t = A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t end
       Type declarations do not match:
         type t = A : { y : 'b; a : 'a; b : 'b; x : 'a; } -> t
       is not included in
         type t = A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t
       Constructors do not match:
         "A : { y : 'b; a : 'a; b : 'b; x : 'a; } -> t"
       is not the same as:
         "A : { x : 'a; a : 'a; b : 'b; y : 'b; } -> t"
       Fields "x" and "y" have been swapped.
|}]


module Not_a_move: sig
  type t = A: { a:'a; b:'b; x:'b} -> t
end = struct
  type t = A: { x:'a; a:'a; b:'b} -> t
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = A: { x:'a; a:'a; b:'b} -> t
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = A : { x : 'a; a : 'a; b : 'b; } -> t end
       is not included in
         sig type t = A : { a : 'a; b : 'b; x : 'b; } -> t end
       Type declarations do not match:
         type t = A : { x : 'a; a : 'a; b : 'b; } -> t
       is not included in
         type t = A : { a : 'a; b : 'b; x : 'b; } -> t
       Constructors do not match:
         "A : { x : 'a; a : 'a; b : 'b; } -> t"
       is not the same as:
         "A : { a : 'a; b : 'b; x : 'b; } -> t"
       1. An extra field, "x", is provided in the first declaration.
       3. A field, "x", is missing in the first declaration.
|}]


module Move: sig
  type t = A: { a:'a; b:'b; x:'b} -> t
end = struct
  type t = A: { x:'b; a:'a; b:'b} -> t
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |   type t = A: { x:'b; a:'a; b:'b} -> t
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig type t = A : { x : 'b; a : 'a; b : 'b; } -> t end
       is not included in
         sig type t = A : { a : 'a; b : 'b; x : 'b; } -> t end
       Type declarations do not match:
         type t = A : { x : 'b; a : 'a; b : 'b; } -> t
       is not included in
         type t = A : { a : 'a; b : 'b; x : 'b; } -> t
       Constructors do not match:
         "A : { x : 'b; a : 'a; b : 'b; } -> t"
       is not the same as:
         "A : { a : 'a; b : 'b; x : 'b; } -> t"
       Field "x" has been moved from position 3 to 1.
|}]


module Imperfect_match: sig
  type t = { a:unit; b:int }
end = struct
 type t = { a:unit; r:unit; c:int; s:unit; b:float }
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |  type t = { a:unit; r:unit; c:int; s:unit; b:float }
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = { a : unit; r : unit; c : int; s : unit; b : float; }
         end
       is not included in
         sig type t = { a : unit; b : int; } end
       Type declarations do not match:
         type t = { a : unit; r : unit; c : int; s : unit; b : float; }
       is not included in
         type t = { a : unit; b : int; }
       2. An extra field, "r", is provided in the first declaration.
       3. An extra field, "c", is provided in the first declaration.
       4. An extra field, "s", is provided in the first declaration.
       5. Fields do not match:
         "b : float;"
       is not the same as:
         "b : int;"
       The type "float" is not equal to the type "int"
|}]


module Very_imperfect_match: sig
  type t = { a:unit; b:int }
end = struct
 type t = { a:unit; r:unit; c:float; s:unit; d:int }
end
[%%expect {|
Lines 3-5, characters 6-3:
3 | ......struct
4 |  type t = { a:unit; r:unit; c:float; s:unit; d:int }
5 | end
Error: Signature mismatch:
       Modules do not match:
         sig
           type t = { a : unit; r : unit; c : float; s : unit; d : int; }
         end
       is not included in
         sig type t = { a : unit; b : int; } end
       Type declarations do not match:
         type t = { a : unit; r : unit; c : float; s : unit; d : int; }
       is not included in
         type t = { a : unit; b : int; }
       2. An extra field, "r", is provided in the first declaration.
       3. An extra field, "c", is provided in the first declaration.
       4. An extra field, "s", is provided in the first declaration.
       5. Fields have different names, "d" and "b".
|}]
