@@ -28,11 +28,11 @@ static TOOLCHAIN_CHANNELS: &[&str] = &[
28
28
"nightly" ,
29
29
"beta" ,
30
30
"stable" ,
31
- // Allow from 1.0.0 through to 9.999.99
32
- r"\d{1}\.\d{1,3}\.\d{1,2}" ,
31
+ // Allow from 1.0.0 through to 9.999.99 with optional patch version
32
+ r"\d{1}\.\d{1,3}(?: \.\d{1,2})? " ,
33
33
] ;
34
34
35
- #[ derive( Debug ) ]
35
+ #[ derive( Debug , PartialEq ) ]
36
36
struct ParsedToolchainDesc {
37
37
channel : String ,
38
38
date : Option < String > ,
@@ -52,7 +52,7 @@ pub struct PartialToolchainDesc {
52
52
pub target : PartialTargetTriple ,
53
53
}
54
54
55
- #[ derive( Debug , Clone ) ]
55
+ #[ derive( Debug , Clone , PartialEq ) ]
56
56
pub struct PartialTargetTriple {
57
57
pub arch : Option < String > ,
58
58
pub os : Option < String > ,
@@ -147,7 +147,7 @@ impl FromStr for ParsedToolchainDesc {
147
147
fn from_str ( desc : & str ) -> Result < Self > {
148
148
lazy_static ! {
149
149
static ref TOOLCHAIN_CHANNEL_PATTERN : String = format!(
150
- r"^({})(?:-(\d{{4}}-\d{{2}}-\d{{2}}))?(?:-(.* ))?$" ,
150
+ r"^({})(?:-(\d{{4}}-\d{{2}}-\d{{2}}))?(?:-(.+ ))?$" ,
151
151
TOOLCHAIN_CHANNELS . join( "|" )
152
152
) ;
153
153
// Note this regex gives you a guaranteed match of the channel (1)
@@ -948,3 +948,135 @@ fn utc_from_manifest_date(date_str: &str) -> Option<Date<Utc>> {
948
948
. ok ( )
949
949
. map ( |date| Utc . from_utc_date ( & date) )
950
950
}
951
+
952
+ #[ cfg( test) ]
953
+ mod tests {
954
+ use super :: * ;
955
+
956
+ #[ test]
957
+ fn test_parsed_toolchain_desc_parse ( ) {
958
+ let success_cases = vec ! [
959
+ ( "nightly" , ( "nightly" , None , None ) ) ,
960
+ ( "beta" , ( "beta" , None , None ) ) ,
961
+ ( "stable" , ( "stable" , None , None ) ) ,
962
+ ( "0.0" , ( "0.0" , None , None ) ) ,
963
+ ( "0.0.0" , ( "0.0.0" , None , None ) ) ,
964
+ ( "0.0.0--" , ( "0.0.0" , None , Some ( "-" ) ) ) , // possibly a bug?
965
+ ( "9.999.99" , ( "9.999.99" , None , None ) ) ,
966
+ ( "0.0.0-anything" , ( "0.0.0" , None , Some ( "anything" ) ) ) ,
967
+ ( "0.0.0-0000-00-00" , ( "0.0.0" , Some ( "0000-00-00" ) , None ) ) ,
968
+ // possibly unexpected behavior, if someone typos a date?
969
+ (
970
+ "0.0.0-00000-000-000" ,
971
+ ( "0.0.0" , None , Some ( "00000-000-000" ) ) ,
972
+ ) ,
973
+ // possibly unexpected behavior, if someone forgets to add target after the hyphen?
974
+ ( "0.0.0-0000-00-00-" , ( "0.0.0" , None , Some ( "0000-00-00-" ) ) ) ,
975
+ (
976
+ "0.0.0-0000-00-00-any-other-thing" ,
977
+ ( "0.0.0" , Some ( "0000-00-00" ) , Some ( "any-other-thing" ) ) ,
978
+ ) ,
979
+ ] ;
980
+
981
+ for ( input, ( channel, date, target) ) in success_cases {
982
+ let parsed = input. parse :: < ParsedToolchainDesc > ( ) ;
983
+ assert ! (
984
+ parsed. is_ok( ) ,
985
+ "expected parsing of `{}` to succeed: {:?}" ,
986
+ input,
987
+ parsed
988
+ ) ;
989
+
990
+ let expected = ParsedToolchainDesc {
991
+ channel : channel. into ( ) ,
992
+ date : date. map ( String :: from) ,
993
+ target : target. map ( String :: from) ,
994
+ } ;
995
+ assert_eq ! ( parsed. unwrap( ) , expected, "input: `{}`" , input) ;
996
+ }
997
+
998
+ let failure_cases = vec ! [ "anything" , "00.0000.000" , "3" , "" , "--" , "0.0.0-" ] ;
999
+
1000
+ for input in failure_cases {
1001
+ let parsed = input. parse :: < ParsedToolchainDesc > ( ) ;
1002
+ assert ! (
1003
+ parsed. is_err( ) ,
1004
+ "expected parsing of `{}` to fail: {:?}" ,
1005
+ input,
1006
+ parsed
1007
+ ) ;
1008
+
1009
+ let error_message = format ! ( "invalid toolchain name: '{}'" , input) ;
1010
+
1011
+ assert_eq ! (
1012
+ parsed. unwrap_err( ) . to_string( ) ,
1013
+ error_message,
1014
+ "input: `{}`" ,
1015
+ input
1016
+ ) ;
1017
+ }
1018
+ }
1019
+
1020
+ #[ test]
1021
+ fn test_partial_target_triple_new ( ) {
1022
+ let success_cases = vec ! [
1023
+ ( "" , ( None , None , None ) ) ,
1024
+ ( "i386" , ( Some ( "i386" ) , None , None ) ) ,
1025
+ ( "pc-windows" , ( None , Some ( "pc-windows" ) , None ) ) ,
1026
+ ( "gnu" , ( None , None , Some ( "gnu" ) ) ) ,
1027
+ ( "i386-gnu" , ( Some ( "i386" ) , None , Some ( "gnu" ) ) ) ,
1028
+ ( "pc-windows-gnu" , ( None , Some ( "pc-windows" ) , Some ( "gnu" ) ) ) ,
1029
+ ( "i386-pc-windows" , ( Some ( "i386" ) , Some ( "pc-windows" ) , None ) ) ,
1030
+ (
1031
+ "i386-pc-windows-gnu" ,
1032
+ ( Some ( "i386" ) , Some ( "pc-windows" ) , Some ( "gnu" ) ) ,
1033
+ ) ,
1034
+ ] ;
1035
+
1036
+ for ( input, ( arch, os, env) ) in success_cases {
1037
+ let partial_target_triple = PartialTargetTriple :: new ( input) ;
1038
+ assert ! (
1039
+ partial_target_triple. is_some( ) ,
1040
+ "expected `{}` to create some partial target triple; got None" ,
1041
+ input
1042
+ ) ;
1043
+
1044
+ let expected = PartialTargetTriple {
1045
+ arch : arch. map ( String :: from) ,
1046
+ os : os. map ( String :: from) ,
1047
+ env : env. map ( String :: from) ,
1048
+ } ;
1049
+
1050
+ assert_eq ! (
1051
+ partial_target_triple. unwrap( ) ,
1052
+ expected,
1053
+ "input: `{}`" ,
1054
+ input
1055
+ ) ;
1056
+ }
1057
+
1058
+ let failure_cases = vec ! [
1059
+ "anything" ,
1060
+ "any-other-thing" ,
1061
+ "-" ,
1062
+ "--" ,
1063
+ "i386-" ,
1064
+ "i386-pc-" ,
1065
+ "i386-pc-windows-" ,
1066
+ "-pc-windows" ,
1067
+ "i386-pc-windows-anything" ,
1068
+ "0000-00-00-" ,
1069
+ "00000-000-000" ,
1070
+ ] ;
1071
+
1072
+ for input in failure_cases {
1073
+ let partial_target_triple = PartialTargetTriple :: new ( input) ;
1074
+ assert ! (
1075
+ partial_target_triple. is_none( ) ,
1076
+ "expected `{}` to be `None`, was: `{:?}`" ,
1077
+ input,
1078
+ partial_target_triple
1079
+ ) ;
1080
+ }
1081
+ }
1082
+ }
0 commit comments