Free cookie consent management tool by TermsFeed Policy Generator

Changeset 1795


Ignore:
Timestamp:
05/14/09 13:00:36 (16 years ago)
Author:
epitzer
Message:

Also make sure major and minor version match (not only newer) + better tests. (#613)

Location:
trunk/sources
Files:
5 edited
1 copied
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeName.cs

    r1794 r1795  
    66
    77namespace HeuristicLab.Persistence.Auxiliary {
    8 
    9   public class ParseError : Exception {
    10     public ParseError(string message) : base(message) { }
    11   }
    12 
    13   public class TypeNameParser {
    14 
    15     /*
    16       TypeSpec := SimpleTypeSpec '&'?
    17 
    18       SimpleTypeSpec := (IDENTIFIER '.')*
    19                         (IDENTIFIER '+')*
    20                          IDENTIFIER
    21                         ( '`\d+[' Generics ']' )?
    22                         (\*|\[(\d+\.\.\d+|\d+\.\.\.|(|\*)(,(|\*))*)\])*
    23                         (',\s*' IDENTIFIER (',\s*' AssemblyProperty)* )?
    24 
    25       Generics := '[' SimpleTypeSpec ']' (',[' SimpleTypeSpec ']')
    26 
    27       AssemblyProperty := 'Version=' Version
    28                  |  'PublicKey(Token)?=[a-fA-F0-9]+'
    29                  |  'Culture=[a-zA-F0-9]+'
    30 
    31       Version := '\d+\.\d+\.\d+\.\d+)'
    32 
    33       IDENTIFIER = [a-zA-Z][a-ZA-Z0-9]*
    34     */
    35 
    36 
    37     class Token {
    38       private static Dictionary<string, string> tokens =
    39         new Dictionary<string, string> {
    40           {"&", "AMPERSAND"},
    41           {".", "DOT"},
    42           {"-", "DASH"},
    43           {"+", "PLUS"},
    44           {",", "COMMA"},
    45           {"[", "OPEN_BRACKET"},
    46           {"]", "CLOSE_BRACKET"},
    47           {"*", "ASTERISK"},
    48           {" ", "SPACE"},
    49           {"=", "EQUALS"},
    50           {"`", "BACKTICK"} };
    51       private static Regex NumberRegex = new Regex("^\\d+$");
    52       private static Regex TokenRegex = new Regex("[-&.+,\\[\\]* =`]|\\d+|[a-zA-Z][a-zA-Z0-9]*");
    53       public string Name { get; private set; }
    54       public string Value { get; private set; }
    55       public int? Number { get; private set; }
    56       public int Position { get; private set; }
    57       private Token(string value, int pos) {
    58         Position = pos;
    59         if (tokens.ContainsKey(value)) {
    60           Name = tokens[value];
    61         } else if (NumberRegex.IsMatch(value)) {
    62           Number = int.Parse(value);
    63         } else {
    64           Value = value;
    65         }
    66       }
    67       public static IEnumerable<Token> Tokenize(string s) {
    68         int pos = 0;
    69         foreach (Match m in TokenRegex.Matches(s)) {
    70           yield return new Token(m.Value, pos);
    71           pos += m.Length;
    72         }
    73       }
    74       public override string ToString() {
    75         if (Name != null)
    76           return "Token(" + Name + ")";
    77         if (Value != null)
    78           return "\"" + Value + "\"";
    79         if (Number != null)
    80           return Number.ToString();
    81         return "<empty>";
    82       }
    83     }
    84 
    85     private Queue<Token> tokens;
    86     private int Position {
    87       get {
    88         if (tokens.Count == 0)
    89           return -1;
    90         else
    91           return tokens.Peek().Position;
    92       }
    93     }
    94 
    95     private TypeNameParser(string s) {
    96       tokens = new Queue<Token>(Token.Tokenize(s));
    97     }
    98 
    99     public static TypeName Parse(string s) {
    100       TypeNameParser p = new TypeNameParser(s);
    101       try {
    102         return p.TransformTypeSpec();
    103       } catch (ParseError x) {
    104         if (p.Position > 0)
    105           throw new ParseError(String.Format(
    106             "Could not parse typename: {0}\n\"{1}====>{2}<===={3}",
    107             x.Message,
    108             s.Substring(0, p.Position),
    109             s[p.Position],
    110             s.Substring(p.Position, s.Length - p.Position)));
    111         else
    112           throw new ParseError(String.Format(
    113             "Could not parse typenname \"{0}\" at end of input: {1}",
    114             s,
    115             x.Message));
    116       }
    117     }
    118 
    119     private TypeName TransformTypeSpec() {
    120       TypeName t = TransformSimpleTypeSpec();
    121       t.IsReference = ConsumeToken("AMPERSAND");
    122       return t;
    123     }
    124 
    125     private TypeName TransformSimpleTypeSpec() {
    126       List<string> nameSpace = new List<string>();
    127       nameSpace.Add(ConsumeIdentifier());
    128       while (ConsumeToken("DOT"))
    129         nameSpace.Add(ConsumeIdentifier());
    130       List<string> className = new List<string>();
    131       if (nameSpace.Count > 0) {
    132         className.Add(nameSpace[nameSpace.Count - 1]);
    133         nameSpace.RemoveAt(nameSpace.Count - 1);
    134       }
    135       while (ConsumeToken("PLUS"))
    136         className.Add(ConsumeIdentifier());
    137       TypeName typeName = new TypeName(
    138         string.Join(".", nameSpace.ToArray()),
    139         string.Join("+", className.ToArray()));
    140       if (ConsumeToken("BACKTICK")) {
    141         int nGenericArgs = ConsumeNumber();
    142         if (ConsumeToken("OPEN_BRACKET") &&
    143           CanConsumeToken("OPEN_BRACKET")) {
    144           typeName.GenericArgs.AddRange(TransformGenerics());
    145           ConsumeToken("CLOSE_BRACKET", true);
    146         }
    147       }
    148       StringBuilder pointerOrArray = new StringBuilder();
    149       while (true) {
    150         if (ConsumeToken("ASTERSIK")) {
    151           pointerOrArray.Append("*");
    152         } else if (ConsumeToken("OPEN_BRACKET")) {
    153           pointerOrArray.Append('[');
    154           ParseDimension(pointerOrArray);
    155           while (ConsumeToken("COMMA")) {
    156             pointerOrArray.Append(",");
    157             ParseDimension(pointerOrArray);
    158           }
    159           ConsumeToken("CLOSE_BRACKET", true);
    160           pointerOrArray.Append(']');
    161         } else {
    162           break;
    163         }
    164       }
    165       typeName.MemoryMagic = pointerOrArray.ToString();
    166       if (ConsumeComma()) {
    167         StringBuilder sb = new StringBuilder();
    168         sb.Append(ConsumeIdentifier());
    169         while (CanConsumeToken("DOT") ||
    170           CanConsumeToken("DASH") ||
    171           CanConsumeNumber() ||
    172           CanConsumeIdentifier()) {
    173           if (ConsumeToken("DOT"))
    174             sb.Append('.');
    175           else if (ConsumeToken("DASH"))
    176             sb.Append('-');
    177           else if (CanConsumeNumber())
    178             sb.Append(ConsumeNumber());
    179           else
    180             sb.Append(ConsumeIdentifier());
    181         }
    182         typeName.AssemblyName = sb.ToString();
    183         while (ConsumeComma()) {
    184           KeyValuePair<string, string> property =
    185             TransformAssemblyProperty();
    186           typeName.AssemblyAttribues.Add(property.Key, property.Value);
    187         }
    188       }
    189       return typeName;
    190     }
    191 
    192     private void ParseDimension(StringBuilder sb) {
    193       if (ConsumeToken("ASTERSIK")) {
    194         sb.Append("*");
    195       } else if (CanConsumeNumber()) {
    196         sb.Append(ConsumeNumber());
    197         ConsumeToken("DOT", true);
    198         ConsumeToken("DOT", true);
    199         if (ConsumeToken("DOT")) {
    200           sb.Append("...");
    201         } else {
    202           sb.Append("..").Append(ConsumeNumber());
    203         }
    204       }
    205     }
    206 
    207     private IEnumerable<TypeName> TransformGenerics() {
    208       ConsumeToken("OPEN_BRACKET", true);
    209       yield return TransformSimpleTypeSpec();
    210       ConsumeToken("CLOSE_BRACKET", true);
    211       while (ConsumeToken("COMMA")) {
    212         ConsumeToken("OPEN_BRACKET", true);
    213         yield return TransformSimpleTypeSpec();
    214         ConsumeToken("CLOSE_BRACKET", true);
    215       }
    216     }
    217 
    218     private KeyValuePair<string, string> TransformAssemblyProperty() {
    219       if (ConsumeIdentifier("Version")) {
    220         ConsumeToken("EQUALS", true);
    221         return new KeyValuePair<string, string>(
    222           "Version",
    223           TransformVersion());
    224       } else if (ConsumeIdentifier("PublicKey")) {
    225         ConsumeToken("EQUALS", true);
    226         return new KeyValuePair<string, string>(
    227           "PublicKey",
    228           ConsumeIdentifier());
    229       } else if (ConsumeIdentifier("PublicKeyToken")) {
    230         ConsumeToken("EQUALS", true);
    231         return new KeyValuePair<string, string>(
    232           "PublicKeyToken",
    233           ConsumeIdentifier());
    234       } else if (ConsumeIdentifier("Culture")) {
    235         ConsumeToken("EQUALS", true);
    236         return new KeyValuePair<string, string>(
    237           "Culture",
    238           ConsumeIdentifier());
    239       } else if (ConsumeIdentifier("Custom")) {
    240         ConsumeToken("EQUALS", true);
    241         return new KeyValuePair<string, string>(
    242           "Custom",
    243           ConsumeIdentifier());
    244       } else {
    245         throw new ParseError(String.Format(
    246           "Invalid assembly property \"{0}\"",
    247           tokens.Peek().ToString()));
    248       }
    249     }
    250     private string TransformVersion() {
    251       StringBuilder version = new StringBuilder();
    252       version.Append(ConsumeNumber());
    253       ConsumeToken("DOT");
    254       version.Append('.').Append(ConsumeNumber());
    255       ConsumeToken("DOT");
    256       version.Append('.').Append(ConsumeNumber());
    257       ConsumeToken("DOT");
    258       version.Append('.').Append(ConsumeNumber());
    259       return version.ToString();
    260     }
    261 
    262     private bool CanConsumeNumber() {
    263       if (tokens.Count == 0)
    264         return false;
    265       return tokens.Peek().Number != null;
    266     }
    267 
    268     private int ConsumeNumber() {
    269       if (tokens.Count == 0)
    270         throw new ParseError("End of input while expecting number");
    271       if (tokens.Peek().Number != null)
    272         return (int)tokens.Dequeue().Number;
    273       throw new ParseError(string.Format(
    274         "Number expected, found \"{0}\" instead",
    275         tokens.Peek().ToString()));
    276     }
    277 
    278     private bool ConsumeIdentifier(string value) {
    279       if (tokens.Count == 0)
    280         return false;
    281       if (tokens.Peek().Value == value) {
    282         tokens.Dequeue();
    283         return true;
    284       } else {
    285         return false;
    286       }
    287     }
    288 
    289     private bool CanConsumeIdentifier() {
    290       return tokens.Count > 0 && tokens.Peek().Value != null;
    291     }
    292 
    293     private string ConsumeIdentifier() {
    294       if (tokens.Count == 0)
    295         throw new ParseError("End of input while expecting identifier");
    296       if (tokens.Peek().Value != null)
    297         return tokens.Dequeue().Value;
    298       throw new ParseError(String.Format(
    299         "Identifier expected, found \"{0}\" instead",
    300         tokens.Peek().ToString()));
    301     }
    302 
    303     private bool ConsumeComma() {
    304       if (ConsumeToken("COMMA")) {
    305         while (ConsumeToken("SPACE")) ;
    306         return true;
    307       } else {
    308         return false;
    309       }
    310     }
    311 
    312     private bool ConsumeToken(string name) {
    313       return ConsumeToken(name, false);
    314     }
    315 
    316     private bool CanConsumeToken(string name) {
    317       if (tokens.Count == 0)
    318         return false;
    319       if (tokens.Peek().Name == name)
    320         return true;
    321       return false;
    322     }
    323 
    324     private bool ConsumeToken(string name, bool force) {
    325       if (tokens.Count == 0)
    326         if (force)
    327           throw new ParseError(String.Format(
    328             "end of input while expecting token \"{0}\"",
    329             name));
    330         else
    331           return false;
    332       if (tokens.Peek().Name == name) {
    333         tokens.Dequeue();
    334         return true;
    335       } else if (force) {
    336         throw new ParseError(String.Format(
    337           "expected \"{0}\" found \"{1}\"",
    338           name,
    339           tokens.Peek().ToString()));
    340       } else {
    341         return false;
    342       }
    343     }
    344 
    345 
    346   }
    347 
     8 
    3489  public class TypeName {
    34910    public string Namespace { get; private set; }
     
    39758    }
    39859
    399     public bool IsOlderThan(TypeName t) {
     60    public bool IsNewerThan(TypeName t) {
    40061      try {
    40162        if (this.ClassName != t.ClassName ||
     
    40566        if (CompareVersions(
    40667          this.AssemblyAttribues["Version"],
    407           t.AssemblyAttribues["Version"]) < 0)
     68          t.AssemblyAttribues["Version"]) > 0)
    40869          return true;
    40970        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
     
    41172        while (thisIt.MoveNext()) {
    41273          tIt.MoveNext();
    413           if (thisIt.Current.IsOlderThan(tIt.Current))
     74          if (thisIt.Current.IsNewerThan(tIt.Current))
    41475            return true;
    41576        }
     
    42081    }
    42182
     83    public bool IsCompatible(TypeName t) {
     84      try {
     85        if (this.ClassName != t.ClassName ||
     86          this.Namespace != t.Namespace ||
     87          this.AssemblyName != t.AssemblyName)
     88          throw new Exception("Cannot compare versions of different types");
     89        Version thisVersion = new Version(this.AssemblyAttribues["Version"]);
     90        Version tVersion = new Version(t.AssemblyAttribues["Version"]);
     91        if (thisVersion.Major != tVersion.Major ||
     92          thisVersion.Minor != tVersion.Minor)
     93          return false;
     94        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
     95        IEnumerator<TypeName> tIt = t.GenericArgs.GetEnumerator();
     96        while (thisIt.MoveNext()) {
     97          tIt.MoveNext();
     98          if (!thisIt.Current.IsCompatible(tIt.Current))
     99            return false;
     100        }
     101        return true;
     102      } catch (KeyNotFoundException) {
     103        throw new Exception("Could not extract version infomration from type string");
     104      }
     105    }
     106
    422107    private static int CompareVersions(string v1string, string v2string) {
    423108      return new Version(v1string).CompareTo(new Version(v2string));
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeNameParser.cs

    r1794 r1795  
    223223          TransformVersion());
    224224      } else if (ConsumeIdentifier("PublicKey")) {
    225         ConsumeToken("EQUALS", true);
    226         return new KeyValuePair<string, string>(
    227           "PublicKey",
    228           ConsumeIdentifier());
     225        return ConsumeAssignment("PublicKey");
    229226      } else if (ConsumeIdentifier("PublicKeyToken")) {
    230         ConsumeToken("EQUALS", true);
    231         return new KeyValuePair<string, string>(
    232           "PublicKeyToken",
    233           ConsumeIdentifier());
     227        return ConsumeAssignment("PublicKeyToken");
    234228      } else if (ConsumeIdentifier("Culture")) {
    235         ConsumeToken("EQUALS", true);
    236         return new KeyValuePair<string, string>(
    237           "Culture",
    238           ConsumeIdentifier());
     229        return ConsumeAssignment("Culture");
    239230      } else if (ConsumeIdentifier("Custom")) {
    240         ConsumeToken("EQUALS", true);
    241         return new KeyValuePair<string, string>(
    242           "Custom",
    243           ConsumeIdentifier());
     231        return ConsumeAssignment("Custom");
    244232      } else {
    245233        throw new ParseError(String.Format(
     
    248236      }
    249237    }
     238
     239    private KeyValuePair<string, string> ConsumeAssignment(string name) {
     240      ConsumeToken("EQUALS", true);
     241      return new KeyValuePair<string, string>(name, ConsumeIdentifier());
     242    }
     243
    250244    private string TransformVersion() {
    251245      StringBuilder version = new StringBuilder();
     
    342336      }
    343337    }
    344 
    345 
    346   }
    347 
    348   public class TypeName {
    349     public string Namespace { get; private set; }
    350     public string ClassName { get; private set; }
    351     public List<TypeName> GenericArgs { get; internal set; }
    352     public bool IsGeneric { get { return GenericArgs.Count > 0; } }
    353     public string MemoryMagic { get; internal set; }
    354     public string AssemblyName { get; internal set; }
    355     public Dictionary<string, string> AssemblyAttribues { get; internal set; }
    356     public bool IsReference { get; internal set; }
    357 
    358     internal TypeName(string nameSpace, string className) {
    359       Namespace = nameSpace;
    360       ClassName = className;
    361       GenericArgs = new List<TypeName>();
    362       MemoryMagic = "";
    363       AssemblyAttribues = new Dictionary<string, string>();
    364     }
    365 
    366     public string ToString(bool full) {
    367       return ToString(full, true);
    368     }
    369 
    370     public string ToString(bool full, bool includeAssembly) {
    371       StringBuilder sb = new StringBuilder();
    372       sb.Append(Namespace).Append('.').Append(ClassName);
    373       if (IsGeneric) {
    374         sb.Append('`').Append(GenericArgs.Count).Append('[');
    375         bool first = true;
    376         foreach (TypeName t in GenericArgs) {
    377           if (first)
    378             first = false;
    379           else
    380             sb.Append(',');
    381           sb.Append('[').Append(t.ToString(full)).Append(']');
    382         }
    383         sb.Append(']');
    384       }
    385       sb.Append(MemoryMagic);
    386       if (includeAssembly && AssemblyName != null) {
    387         sb.Append(", ").Append(AssemblyName);
    388         if (full)
    389           foreach (var property in AssemblyAttribues)
    390             sb.Append(", ").Append(property.Key).Append('=').Append(property.Value);
    391       }
    392       return sb.ToString();
    393     }
    394 
    395     public override string ToString() {
    396       return ToString(true);
    397     }
    398 
    399     public bool IsOlderThan(TypeName t) {
    400       try {
    401         if (this.ClassName != t.ClassName ||
    402           this.Namespace != t.Namespace ||
    403           this.AssemblyName != t.AssemblyName)
    404           throw new Exception("Cannot compare versions of different types");
    405         if (CompareVersions(
    406           this.AssemblyAttribues["Version"],
    407           t.AssemblyAttribues["Version"]) < 0)
    408           return true;
    409         IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
    410         IEnumerator<TypeName> tIt = t.GenericArgs.GetEnumerator();
    411         while (thisIt.MoveNext()) {
    412           tIt.MoveNext();
    413           if (thisIt.Current.IsOlderThan(tIt.Current))
    414             return true;
    415         }
    416         return false;
    417       } catch (KeyNotFoundException) {
    418         throw new Exception("Could not extract version information from type string");
    419       }
    420     }
    421 
    422     private static int CompareVersions(string v1string, string v2string) {
    423       return new Version(v1string).CompareTo(new Version(v2string));
    424     }
    425338  }
    426339}
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs

    r1780 r1795  
    1717      } catch (Exception) {
    1818        Logger.Warn(String.Format(
    19           "Cannot load type \"{0}\", falling back to loading with partial name", typeNameString));
     19          "Cannot load type \"{0}\", falling back to partial name", typeNameString));
    2020        try {
    2121          TypeName typeName = TypeNameParser.Parse(typeNameString);
     
    2828        }
    2929        try {
    30           if (
    31             TypeNameParser.Parse(type.AssemblyQualifiedName).IsOlderThan(
    32             TypeNameParser.Parse(typeNameString)))
     30          TypeName requestedTypeName = TypeNameParser.Parse(typeNameString);
     31          TypeName loadedTypeName = TypeNameParser.Parse(type.AssemblyQualifiedName);
     32          if (!requestedTypeName.IsCompatible(loadedTypeName))
     33            throw new PersistenceException(String.Format(
     34              "Serialized type is incompatible with available type: serialized: {0}, loaded: {1}",
     35              typeNameString,
     36              type.AssemblyQualifiedName));
     37          if (requestedTypeName.IsNewerThan(loadedTypeName))
    3338            throw new PersistenceException(String.Format(
    3439              "Serialized type is newer than available type: serialized: {0}, loaded: {1}",
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/Serializer.cs

    r1780 r1795  
    4545            serializer = d.GetType().AssemblyQualifiedName;
    4646          }
    47           //result.Add(new TypeMapping(pair.Value, pair.Key.AssemblyQualifiedName, serializer));
    48           result.Add(new TypeMapping(pair.Value, pair.Key.VersionInvariantName(), serializer));
     47          result.Add(new TypeMapping(pair.Value, pair.Key.AssemblyQualifiedName, serializer));
    4948        }
    5049        return result;
  • trunk/sources/HeuristicLab.Persistence/3.3/HeuristicLab.Persistence-3.3.csproj

    r1712 r1795  
    9393  </ItemGroup>
    9494  <ItemGroup>
     95    <Compile Include="Auxiliary\TypeNameParser.cs" />
    9596    <Compile Include="Auxiliary\ReflectionTools.cs" />
    9697    <Compile Include="Core\Configuration.cs" />
     
    104105    <Compile Include="Auxiliary\TypeExtensions.cs" />
    105106    <Compile Include="Core\TypeMapping.cs" />
    106     <Compile Include="Auxiliary\TypeStringBuilder.cs" />
     107    <Compile Include="Auxiliary\TypeName.cs" />
    107108    <Compile Include="Core\GeneratorBase.cs" />
    108109    <Compile Include="Default\DebugString\DebugString.cs" />
  • trunk/sources/HeuristicLab.Persistence/UnitTests/UseCases.cs

    r1780 r1795  
    550550      IntWrapper newI = (IntWrapper)d.Deserialize(p);
    551551      Assert.AreEqual(i.Value, newI.Value);
     552
    552553      string newTypeString = Regex.Replace(typeString.ToString(),
    553         "Version=(\\d+\\.\\d+\\.\\d+\\.\\d+)",
    554         "Version=9999.9999.9999.9999");
     554        "Version=\\d+\\.\\d+\\.\\d+\\.\\d+",
     555        "Version=0.0.9999.9999");
    555556      try {
    556557        d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString)));
    557558        Assert.Fail("Exception expected");
    558       } catch (PersistenceException) {
    559         // EXPECTED
     559      } catch (PersistenceException x) {
     560        Assert.IsTrue(x.Message.Contains("incompatible"));
     561      }
     562      newTypeString = Regex.Replace(typeString.ToString(),
     563        "Version=(\\d+\\.\\d+)\\.\\d+\\.\\d+",
     564        "Version=$1.9999.9999");
     565      try {
     566        d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString)));
     567        Assert.Fail("Exception expected");
     568      } catch (PersistenceException x) {
     569        Assert.IsTrue(x.Message.Contains("newer"));
    560570      }
    561571    }
  • trunk/sources/HeuristicLab.sln

    r1778 r1795  
    200200EndProject
    201201Global
     202  GlobalSection(TestCaseManagementSettings) = postSolution
     203    CategoryFile = HeuristicLab.vsmdi
     204  EndGlobalSection
    202205  GlobalSection(SolutionConfigurationPlatforms) = preSolution
    203206    CEDMA Debug|Any CPU = CEDMA Debug|Any CPU
Note: See TracChangeset for help on using the changeset viewer.