Skip to content

Commit c3ec050

Browse files
author
Christian Lindig
committed
CA-408048 add library to represent version strings
We want to handle version strings reliably and not re-doscovering their problems over and over. Add a simple library together with tests. Signed-off-by: Christian Lindig <[email protected]>
1 parent 0441299 commit c3ec050

File tree

5 files changed

+196
-0
lines changed

5 files changed

+196
-0
lines changed

ocaml/xapi-aux/dune

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(library
22
(name xapi_aux)
33
(modes best)
4+
(modules :standard \ version_test)
45
(libraries
56
astring
67
clock
@@ -21,3 +22,11 @@
2122
(wrapped false)
2223
)
2324

25+
; to run this test: dune exec ./version_test.exe
26+
(tests
27+
(names version_test)
28+
(modes (best exe))
29+
(modules version_test)
30+
(package xapi)
31+
(libraries
32+
xapi_aux alcotest))

ocaml/xapi-aux/version.ml

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
(*
2+
Copyright (c) Cloud Software Group, Inc.
3+
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published
6+
by the Free Software Foundation; version 2.1 only. with the special
7+
exception on linking described in file LICENSE.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
*)
14+
15+
(* Simple abstraction for version information that enforces a simple
16+
format and predicatable semantics *)
17+
18+
exception Format of string
19+
20+
(** in decreasing oder of sginificance *)
21+
type t = int list
22+
23+
let of_string str =
24+
let int str = Scanf.sscanf str "%u%!" Fun.id in
25+
try String.split_on_char '.' str |> List.map int with _ -> raise (Format str)
26+
27+
let to_string t =
28+
let str int = Printf.sprintf "%d" int in
29+
t |> List.map str |> String.concat "."
30+
31+
(** Total order over versions; 1.2.3 is equal to 1.2.3.0 *)
32+
let rec compare v1 v2 =
33+
match (v1, v2) with
34+
| [], [] ->
35+
0
36+
| 0 :: xs, [] ->
37+
compare xs []
38+
| _, [] ->
39+
1
40+
| [], 0 :: ys ->
41+
compare [] ys
42+
| [], _ ->
43+
-1
44+
| x :: xs, y :: ys when x = y ->
45+
compare xs ys
46+
| x :: _, y :: _ when x < y ->
47+
-1
48+
| _ ->
49+
1
50+
51+
let ne x y = compare x y <> 0
52+
53+
let eq x y = compare x y = 0
54+
55+
let le x y = compare x y <= 0
56+
57+
let ge x y = compare x y >= 0
58+
59+
let gt x y = compare x y > 0
60+
61+
let lt x y = compare x y < 0
62+
63+
let is_valid str =
64+
try
65+
ignore (of_string str) ;
66+
true
67+
with Format _ -> false
68+
69+
module String = struct
70+
let wrap f v1 v2 = f (of_string v1) (of_string v2)
71+
72+
let compare = wrap compare
73+
74+
let ne = wrap ne
75+
76+
let eq = wrap eq
77+
78+
let le = wrap le
79+
80+
let ge = wrap ge
81+
82+
let gt = wrap gt
83+
84+
let lt = wrap lt
85+
end

ocaml/xapi-aux/version.mli

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
(*
2+
Copyright (c) Cloud Software Group, Inc.
3+
4+
This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published
6+
by the Free Software Foundation; version 2.1 only. with the special
7+
exception on linking described in file LICENSE.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
*)
14+
15+
(** a version, derived from a string representation - see below *)
16+
type t
17+
18+
(** A version string violates the supported syntax *)
19+
exception Format of string
20+
21+
val of_string : string -> t
22+
(** Parse a version; may raise [Format]. A version is a sequence of
23+
unsigned integers separated by a dot; for axample "1.2.3" is a legal
24+
version. Must have at least one component. Examples:
25+
- 3
26+
- 3.10
27+
- 3.10.4
28+
- 3.10.4.0.0
29+
- 3.10.4.0.1
30+
- 0
31+
- 0.2
32+
*)
33+
34+
val to_string : t -> string
35+
(** represent a version as a string *)
36+
37+
val compare : t -> t -> int
38+
(** Total order over versions; yields one of -1, 0, 1 as by convention.
39+
- 1.2.3 = 1.2.3.0
40+
- 1.10.2 > 1.9.1
41+
- 0.1.0.0 = 0.1
42+
*)
43+
44+
(* version equality relations *)
45+
val eq : t -> t -> bool
46+
47+
val ge : t -> t -> bool
48+
49+
val gt : t -> t -> bool
50+
51+
val le : t -> t -> bool
52+
53+
val lt : t -> t -> bool
54+
55+
val ne : t -> t -> bool
56+
57+
(* Validate the format of a version string *)
58+
val is_valid : string -> bool
59+
60+
(* Operations over version strings for convenience. Each function may
61+
raise [Format] *)
62+
module String : sig
63+
val compare : string -> string -> int
64+
65+
val ne : string -> string -> bool
66+
67+
val eq : string -> string -> bool
68+
69+
val le : string -> string -> bool
70+
71+
val ge : string -> string -> bool
72+
73+
val gt : string -> string -> bool
74+
75+
val lt : string -> string -> bool
76+
end

ocaml/xapi-aux/version_test.ml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
open Alcotest
2+
3+
let format () =
4+
check bool __LOC__ true (Version.is_valid "3") ;
5+
check bool __LOC__ true (Version.is_valid "0") ;
6+
check bool __LOC__ true (Version.is_valid "3.1") ;
7+
check bool __LOC__ true (Version.is_valid "3.1.4") ;
8+
check bool __LOC__ true (Version.is_valid "3.14") ;
9+
check bool __LOC__ false (Version.is_valid "") ;
10+
check bool __LOC__ false (Version.is_valid "3a") ;
11+
check bool __LOC__ false (Version.is_valid "3.1.4.") ;
12+
check bool __LOC__ false (Version.is_valid "3.1.4.a") ;
13+
check bool __LOC__ false (Version.is_valid "3.1.4a") ;
14+
check bool __LOC__ false (Version.is_valid "3.1:4") ;
15+
check bool __LOC__ false (Version.is_valid "-3.1.4")
16+
17+
let order () =
18+
check bool __LOC__ true (Version.String.eq "3" "3.0.0") ;
19+
check bool __LOC__ true (Version.String.le "3" "3.0.1") ;
20+
check bool __LOC__ true (Version.String.le "3.1" "3.10") ;
21+
check bool __LOC__ true (Version.String.eq "0" "0.0.0")
22+
23+
let tests = [test_case "format" `Quick format; test_case "order" `Quick order]
24+
25+
let () = run __MODULE__ [(__MODULE__, tests)]

ocaml/xapi-aux/version_test.mli

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(* empty *)

0 commit comments

Comments
 (0)