2 // verifier.cs: compares two assemblies and reports differences.
5 // Sergey Chaban (serge@wildwestsoftware.com)
7 // (C) Sergey Chaban (serge@wildwestsoftware.com)
12 using System
.Collections
;
13 using System
.Reflection
;
15 namespace Mono
.Verifier
{
19 ////////////////////////////////
21 ////////////////////////////////
23 public abstract class MemberCollection
: IEnumerable
{
25 public delegate MemberInfo
[] InfoQuery (Type type
, BindingFlags bindings
);
26 public delegate bool MemberComparer (MemberInfo mi1
, MemberInfo mi2
);
28 protected SortedList list
;
29 protected MemberComparer comparer
;
31 protected BindingFlags bindings
;
33 protected MemberCollection (Type type
, InfoQuery query
, MemberComparer comparer
, BindingFlags bindings
)
36 throw new NullReferenceException ("Invalid query delegate.");
39 throw new NullReferenceException ("Invalid comparer.");
41 this.comparer
= comparer
;
42 this.bindings
= bindings
;
44 this.list
= new SortedList ();
46 MemberInfo
[] data
= query (type
, bindings
);
47 foreach (MemberInfo info
in data
) {
48 this.list
[info
.Name
] = info
;
54 public MemberInfo
this [string name
] {
56 return list
[name
] as MemberInfo
;
61 public override int GetHashCode ()
63 return list
.GetHashCode ();
67 public override bool Equals (object o
)
69 bool res
= (o
is MemberCollection
);
71 MemberCollection another
= o
as MemberCollection
;
72 IEnumerator it
= GetEnumerator ();
73 while (it
.MoveNext () && res
) {
74 MemberInfo inf1
= it
.Current
as MemberInfo
;
75 MemberInfo inf2
= another
[inf1
.Name
];
76 res
&= comparer (inf1
, inf2
);
84 public static bool operator == (MemberCollection c1
, MemberCollection c2
)
86 return c1
.Equals (c2
);
89 public static bool operator != (MemberCollection c1
, MemberCollection c2
)
96 public IEnumerator
GetEnumerator()
98 return new Iterator (this);
102 internal class Iterator
: IEnumerator
{
103 private MemberCollection host
;
106 internal Iterator (MemberCollection host
)
112 /// <summary></summary>
113 public object Current
116 if (host
!= null && pos
>=0 && pos
< host
.list
.Count
) {
117 return host
.list
.GetByIndex (pos
);
124 /// <summary></summary>
125 public bool MoveNext ()
128 return (++pos
) < host
.list
.Count
;
134 /// <summary></summary>
146 //--- Method collections
149 /// Abstract collection of class' methods.
151 public abstract class MethodCollectionBase
: MemberCollection
{
154 protected MethodCollectionBase (Type type
, BindingFlags bindings
)
155 : base (type
, new InfoQuery (Query
), new MemberComparer (Comparer
), bindings
)
160 private static MemberInfo
[] Query (Type type
, BindingFlags bindings
)
162 // returns MethodInfo []
163 return type
.GetMethods (bindings
);
166 private static bool Comparer (MemberInfo mi1
, MemberInfo mi2
)
169 if (mi1
is MethodInfo
&& (mi2
== null || mi2
is MethodInfo
)) {
170 MethodInfo inf1
= mi1
as MethodInfo
;
171 MethodInfo inf2
= mi2
as MethodInfo
;
172 res
= Compare
.Methods (inf1
, inf2
);
174 Verifier
.log
.Write ("internal-error", "Wrong comparer arguments.", ImportanceLevel
.HIGH
);
183 /// Collection of public instance methods of a class.
185 public class PublicMethods
: MethodCollectionBase
{
187 public PublicMethods (Type type
)
188 : base (type
, BindingFlags
.Public
| BindingFlags
.Instance
)
194 /// Collection of public static methods of a class.
196 public class PublicStaticMethods
: MethodCollectionBase
{
198 public PublicStaticMethods (Type type
)
199 : base (type
, BindingFlags
.Public
| BindingFlags
.Static
)
205 /// Collection of non-public instance methods of a class.
207 public class NonPublicMethods
: MethodCollectionBase
{
209 public NonPublicMethods (Type type
)
210 : base (type
, BindingFlags
.NonPublic
| BindingFlags
.Instance
)
216 /// Collection of non-public static methods of a class.
218 public class NonPublicStaticMethods
: MethodCollectionBase
{
220 public NonPublicStaticMethods (Type type
)
221 : base (type
, BindingFlags
.NonPublic
| BindingFlags
.Static
)
230 //--- Field collections
232 public abstract class FieldCollectionBase
: MemberCollection
{
235 protected FieldCollectionBase (Type type
, BindingFlags bindings
)
236 : base (type
, new InfoQuery (Query
), new MemberComparer (Comparer
), bindings
)
241 private static MemberInfo
[] Query (Type type
, BindingFlags bindings
)
243 // returns FieldInfo []
244 return type
.GetFields (bindings
);
247 private static bool Comparer (MemberInfo mi1
, MemberInfo mi2
)
250 if (mi1
is FieldInfo
&& (mi2
== null || mi2
is FieldInfo
)) {
251 FieldInfo inf1
= mi1
as FieldInfo
;
252 FieldInfo inf2
= mi2
as FieldInfo
;
253 res
= Compare
.Fields (inf1
, inf2
);
255 Verifier
.log
.Write ("internal-error", "Wrong comparer arguments.", ImportanceLevel
.HIGH
);
262 public class PublicFields
: FieldCollectionBase
{
264 public PublicFields (Type type
)
265 : base (type
, BindingFlags
.Public
| BindingFlags
.Instance
)
270 public class PublicStaticFields
: FieldCollectionBase
{
272 public PublicStaticFields (Type type
)
273 : base (type
, BindingFlags
.Public
| BindingFlags
.Static
)
278 public class NonPublicFields
: FieldCollectionBase
{
280 public NonPublicFields (Type type
)
281 : base (type
, BindingFlags
.NonPublic
| BindingFlags
.Instance
)
286 public class NonPublicStaticFields
: FieldCollectionBase
{
288 public NonPublicStaticFields (Type type
)
289 : base (type
, BindingFlags
.NonPublic
| BindingFlags
.Static
)
298 public abstract class AbstractTypeStuff
{
299 public readonly Type type
;
301 public AbstractTypeStuff (Type type
)
304 throw new NullReferenceException ("Invalid type.");
309 public override int GetHashCode ()
311 return type
.GetHashCode ();
314 public static bool operator == (AbstractTypeStuff t1
, AbstractTypeStuff t2
)
316 if ((t1
as object) == null) {
317 if ((t2
as object) == null) return true;
320 return t1
.Equals (t2
);
323 public static bool operator != (AbstractTypeStuff t1
, AbstractTypeStuff t2
)
328 public override bool Equals (object o
)
330 return (o
is AbstractTypeStuff
&& CompareTypes (o
as AbstractTypeStuff
));
333 protected virtual bool CompareTypes (AbstractTypeStuff that
)
335 Verifier
.Log
.Write ("info", "Comparing types.", ImportanceLevel
.LOW
);
338 res
= Compare
.Types (this.type
, that
.type
);
349 /// Represents a class.
351 public class ClassStuff
: AbstractTypeStuff
{
353 public PublicMethods publicMethods
;
354 public PublicStaticMethods publicStaticMethods
;
355 public NonPublicMethods nonpublicMethods
;
356 public NonPublicStaticMethods nonpublicStaticMethods
;
358 public PublicFields publicFields
;
359 public PublicStaticFields publicStaticFields
;
360 public NonPublicFields nonpublicFields
;
361 public NonPublicStaticFields nonpublicStaticFields
;
363 public ClassStuff (Type type
) : base (type
)
365 publicMethods
= new PublicMethods (type
);
366 publicStaticMethods
= new PublicStaticMethods (type
);
367 nonpublicMethods
= new NonPublicMethods (type
);
368 nonpublicStaticMethods
= new NonPublicStaticMethods (type
);
370 publicFields
= new PublicFields (type
);
371 publicStaticFields
= new PublicStaticFields (type
);
372 nonpublicFields
= new NonPublicFields (type
);
373 nonpublicStaticFields
= new NonPublicStaticFields (type
);
377 public override int GetHashCode ()
379 return base.GetHashCode ();
382 private bool CompareMethods (ClassStuff that
)
387 Verifier
.Log
.Write ("info", "Comparing public instance methods.", ImportanceLevel
.LOW
);
388 ok
= (this.publicMethods
== that
.publicMethods
);
390 if (!ok
&& Verifier
.stopOnError
) return res
;
392 Verifier
.Log
.Write ("info", "Comparing public static methods.", ImportanceLevel
.LOW
);
393 ok
= (this.publicStaticMethods
== that
.publicStaticMethods
);
395 if (!ok
&& Verifier
.stopOnError
) return res
;
397 Verifier
.Log
.Write ("info", "Comparing non-public instance methods.", ImportanceLevel
.LOW
);
398 ok
= (this.nonpublicMethods
== that
.nonpublicMethods
);
400 if (!ok
&& Verifier
.stopOnError
) return res
;
402 Verifier
.Log
.Write ("info", "Comparing non-public static methods.", ImportanceLevel
.LOW
);
403 ok
= (this.nonpublicStaticMethods
== that
.nonpublicStaticMethods
);
405 if (!ok
&& Verifier
.stopOnError
) return res
;
411 private bool CompareFields (ClassStuff that
)
416 Verifier
.Log
.Write ("info", "Comparing public instance fields.", ImportanceLevel
.LOW
);
417 ok
= (this.publicFields
== that
.publicFields
);
419 if (!ok
&& Verifier
.stopOnError
) return res
;
421 Verifier
.Log
.Write ("info", "Comparing public static fields.", ImportanceLevel
.LOW
);
422 ok
= (this.publicStaticFields
== that
.publicStaticFields
);
424 if (!ok
&& Verifier
.stopOnError
) return res
;
426 Verifier
.Log
.Write ("info", "Comparing non-public instance fields.", ImportanceLevel
.LOW
);
427 ok
= (this.nonpublicFields
== that
.nonpublicFields
);
429 if (!ok
&& Verifier
.stopOnError
) return res
;
431 Verifier
.Log
.Write ("info", "Comparing non-public static fields.", ImportanceLevel
.LOW
);
432 ok
= (this.nonpublicStaticFields
== that
.nonpublicStaticFields
);
434 if (!ok
&& Verifier
.stopOnError
) return res
;
440 public override bool Equals (object o
)
442 bool res
= (o
is ClassStuff
);
444 ClassStuff that
= o
as ClassStuff
;
446 res
&= this.CompareTypes (that
);
447 if (!res
&& Verifier
.stopOnError
) return res
;
449 res
&= this.CompareMethods (that
);
450 if (!res
&& Verifier
.stopOnError
) return res
;
452 res
&= this.CompareFields (that
);
453 if (!res
&& Verifier
.stopOnError
) return res
;
464 /// Represents an interface.
466 public class InterfaceStuff
: AbstractTypeStuff
{
468 public PublicMethods publicMethods
;
470 public InterfaceStuff (Type type
) : base (type
)
472 publicMethods
= new PublicMethods (type
);
475 public override int GetHashCode ()
477 return base.GetHashCode ();
480 public override bool Equals (object o
)
482 bool res
= (o
is InterfaceStuff
);
485 InterfaceStuff that
= o
as InterfaceStuff
;
487 res
= this.CompareTypes (that
);
488 if (!res
&& Verifier
.stopOnError
) return res
;
490 Verifier
.Log
.Write ("info", "Comparing interface methods.", ImportanceLevel
.LOW
);
491 ok
= (this.publicMethods
== that
.publicMethods
);
493 if (!ok
&& Verifier
.stopOnError
) return res
;
503 /// Represents an enumeration.
505 public class EnumStuff
: AbstractTypeStuff
{
507 //public FieldInfo [] members;
509 public string baseType
;
510 public Hashtable enumTable
;
513 public EnumStuff (Type type
) : base (type
)
515 //members = type.GetFields (BindingFlags.Public | BindingFlags.Static);
517 Array values
= Enum
.GetValues (type
);
518 Array names
= Enum
.GetNames (type
);
520 baseType
= Enum
.GetUnderlyingType (type
).Name
;
522 enumTable
= new Hashtable ();
524 object [] attrs
= type
.GetCustomAttributes (false);
525 isFlags
= (attrs
!= null && attrs
.Length
> 0);
527 foreach (object attr
in attrs
) {
528 isFlags
|= (attr
is FlagsAttribute
);
533 foreach (string id
in names
) {
534 enumTable
[id
] = Convert
.ToInt64(values
.GetValue(indx
) as Enum
);
539 public override int GetHashCode ()
541 return base.GetHashCode ();
544 public override bool Equals (object o
)
546 bool res
= (o
is EnumStuff
);
550 EnumStuff that
= o
as EnumStuff
;
551 ok
= this.CompareTypes (that
);
553 if (!ok
&& Verifier
.stopOnError
) return res
;
555 ok
= (this.baseType
== that
.baseType
);
558 Verifier
.log
.Write ("error",
559 String
.Format ("Underlying types mismatch [{0}, {1}].", this.baseType
, that
.baseType
),
560 ImportanceLevel
.MEDIUM
);
561 if (Verifier
.stopOnError
) return res
;
564 Verifier
.Log
.Write ("info", "Comparing [Flags] attribute.");
565 ok
= !(this.isFlags ^ that
.isFlags
);
568 Verifier
.log
.Write ("error",
569 String
.Format ("[Flags] attribute mismatch ({0} : {1}).", this.isFlags
? "Yes" : "No", that
.isFlags
? "Yes" : "No"),
570 ImportanceLevel
.MEDIUM
);
571 if (Verifier
.stopOnError
) return res
;
574 Verifier
.Log
.Write ("info", "Comparing enum values.");
576 ICollection names
= enumTable
.Keys
;
577 foreach (string id
in names
) {
578 ok
= that
.enumTable
.ContainsKey (id
);
581 Verifier
.log
.Write ("error", String
.Format("{0} absent in enumeration.", id
),
582 ImportanceLevel
.MEDIUM
);
583 if (Verifier
.stopOnError
) return res
;
587 long val1
= (long) this.enumTable
[id
];
588 long val2
= (long) that
.enumTable
[id
];
592 Verifier
.log
.Write ("error",
593 String
.Format ("Enum values mismatch [{0}: {1} != {2}].", id
, val1
, val2
),
594 ImportanceLevel
.MEDIUM
);
595 if (Verifier
.stopOnError
) return res
;
606 public sealed class TypeArray
{
607 public static readonly TypeArray empty
= new TypeArray (Type
.EmptyTypes
);
609 public Type
[] types
;
611 public TypeArray (Type
[] types
)
613 this.types
= new Type
[types
.Length
];
614 for (int i
= 0; i
< types
.Length
; i
++) {
615 this.types
.SetValue (types
.GetValue (i
), i
);
622 public class AssemblyLoader
{
623 public delegate void Hook (TypeArray assemblyTypes
);
625 private static Hashtable cache
;
629 static AssemblyLoader ()
631 cache
= new Hashtable (11);
634 public AssemblyLoader (Hook hook
)
637 throw new NullReferenceException ("Invalid loader hook.");
643 public bool LoadFrom (string assemblyName
)
647 TypeArray types
= TypeArray
.empty
;
650 if (cache
.Contains (assemblyName
)) {
651 types
= (cache
[assemblyName
] as TypeArray
);
652 if (types
== null) types
= TypeArray
.empty
;
654 Assembly asm
= Assembly
.LoadFrom (assemblyName
);
655 Type
[] allTypes
= asm
.GetTypes ();
656 if (allTypes
== null) allTypes
= Type
.EmptyTypes
;
657 types
= new TypeArray (allTypes
);
658 cache
[assemblyName
] = types
;
663 } catch (ReflectionTypeLoadException rtle
) {
664 // FIXME: Should we try to recover? Use loaded portion of types.
665 Type
[] loaded
= rtle
.Types
;
666 for (int i
= 0, xCnt
= 0; i
< loaded
.Length
; i
++) {
667 if (loaded
[i
] == null) {
668 Verifier
.log
.Write ("fatal error",
669 String
.Format ("Unable to load {0}, reason - {1}", loaded
[i
], rtle
.LoaderExceptions
[xCnt
++]),
670 ImportanceLevel
.LOW
);
673 } catch (FileNotFoundException fnfe
) {
674 Verifier
.log
.Write ("fatal error", fnfe
.ToString (), ImportanceLevel
.LOW
);
675 } catch (Exception x
) {
676 Verifier
.log
.Write ("fatal error", x
.ToString (), ImportanceLevel
.LOW
);
687 public abstract class AbstractTypeCollection
: SortedList
{
689 private AssemblyLoader loader
;
691 public AbstractTypeCollection ()
693 loader
= new AssemblyLoader (new AssemblyLoader
.Hook (LoaderHook
));
696 public AbstractTypeCollection (string assemblyName
) : this ()
698 LoadFrom (assemblyName
);
701 public abstract void LoaderHook (TypeArray types
);
704 public bool LoadFrom (string assemblyName
)
706 return loader
.LoadFrom (assemblyName
);
713 public class ClassCollection
: AbstractTypeCollection
{
715 public ClassCollection () : base ()
719 public ClassCollection (string assemblyName
)
720 : base (assemblyName
)
725 public override void LoaderHook (TypeArray types
)
727 foreach (Type type
in types
.types
) {
729 this [type
.FullName
] = new ClassStuff (type
);
737 public class InterfaceCollection
: AbstractTypeCollection
{
739 public InterfaceCollection () : base ()
743 public InterfaceCollection (string assemblyName
)
744 : base (assemblyName
)
749 public override void LoaderHook (TypeArray types
)
751 foreach (Type type
in types
.types
) {
752 if (type
.IsInterface
) {
753 this [type
.FullName
] = new InterfaceStuff (type
);
762 public class EnumCollection
: AbstractTypeCollection
{
764 public EnumCollection () : base ()
768 public EnumCollection (string assemblyName
)
769 : base (assemblyName
)
773 public override void LoaderHook (TypeArray types
)
775 foreach (Type type
in types
.types
) {
777 this [type
.FullName
] = new EnumStuff (type
);
785 public class AssemblyStuff
{
790 public ClassCollection classes
;
791 public InterfaceCollection interfaces
;
792 public EnumCollection enums
;
795 protected delegate bool Comparer (AssemblyStuff asm1
, AssemblyStuff asm2
);
796 private static ArrayList comparers
;
798 static AssemblyStuff ()
800 comparers
= new ArrayList ();
801 comparers
.Add (new Comparer (CompareNumClasses
));
802 comparers
.Add (new Comparer (CompareNumInterfaces
));
803 comparers
.Add (new Comparer (CompareClasses
));
804 comparers
.Add (new Comparer (CompareInterfaces
));
805 comparers
.Add (new Comparer (CompareEnums
));
808 protected static bool CompareNumClasses (AssemblyStuff asm1
, AssemblyStuff asm2
)
810 bool res
= (asm1
.classes
.Count
== asm2
.classes
.Count
);
811 if (!res
) Verifier
.Log
.Write ("error", "Number of classes mismatch.", ImportanceLevel
.MEDIUM
);
815 protected static bool CompareNumInterfaces (AssemblyStuff asm1
, AssemblyStuff asm2
)
817 bool res
= (asm1
.interfaces
.Count
== asm2
.interfaces
.Count
);
818 if (!res
) Verifier
.Log
.Write ("error", "Number of interfaces mismatch.", ImportanceLevel
.MEDIUM
);
823 protected static bool CompareClasses (AssemblyStuff asm1
, AssemblyStuff asm2
)
826 Verifier
.Log
.Write ("info", "Comparing classes.");
828 foreach (DictionaryEntry c
in asm1
.classes
) {
829 string className
= c
.Key
as string;
831 if (Verifier
.Excluded
.Contains (className
)) {
832 Verifier
.Log
.Write ("info", String
.Format ("Ignoring class {0}.", className
), ImportanceLevel
.MEDIUM
);
836 Verifier
.Log
.Write ("class", className
);
838 ClassStuff class1
= c
.Value
as ClassStuff
;
839 ClassStuff class2
= asm2
.classes
[className
] as ClassStuff
;
841 if (class2
== null) {
842 Verifier
.Log
.Write ("error", String
.Format ("There is no such class in {0}", asm2
.name
));
844 if (Verifier
.stopOnError
|| !Verifier
.ignoreMissingTypes
) return res
;
848 res
&= (class1
== class2
);
849 if (!res
&& Verifier
.stopOnError
) return res
;
856 protected static bool CompareInterfaces (AssemblyStuff asm1
, AssemblyStuff asm2
)
859 Verifier
.Log
.Write ("info", "Comparing interfaces.");
861 foreach (DictionaryEntry ifc
in asm1
.interfaces
) {
862 string ifcName
= ifc
.Key
as string;
863 Verifier
.Log
.Write ("interface", ifcName
);
865 InterfaceStuff ifc1
= ifc
.Value
as InterfaceStuff
;
866 InterfaceStuff ifc2
= asm2
.interfaces
[ifcName
] as InterfaceStuff
;
869 Verifier
.Log
.Write ("error", String
.Format ("There is no such interface in {0}", asm2
.name
));
871 if (Verifier
.stopOnError
|| !Verifier
.ignoreMissingTypes
) return res
;
875 res
&= (ifc1
== ifc2
);
876 if (!res
&& Verifier
.stopOnError
) return res
;
884 protected static bool CompareEnums (AssemblyStuff asm1
, AssemblyStuff asm2
)
887 Verifier
.Log
.Write ("info", "Comparing enums.");
889 foreach (DictionaryEntry e
in asm1
.enums
) {
890 string enumName
= e
.Key
as string;
891 Verifier
.Log
.Write ("enum", enumName
);
893 EnumStuff e1
= e
.Value
as EnumStuff
;
894 EnumStuff e2
= asm2
.enums
[enumName
] as EnumStuff
;
897 Verifier
.Log
.Write ("error", String
.Format ("There is no such enum in {0}", asm2
.name
));
899 if (Verifier
.stopOnError
|| !Verifier
.ignoreMissingTypes
) return res
;
903 if (!res
&& Verifier
.stopOnError
) return res
;
911 public AssemblyStuff (string assemblyName
)
913 this.name
= assemblyName
;
922 classes
= new ClassCollection ();
923 ok
= classes
.LoadFrom (name
);
925 if (!ok
) Verifier
.log
.Write ("error", String
.Format ("Unable to load classes from {0}.", name
), ImportanceLevel
.HIGH
);
927 interfaces
= new InterfaceCollection ();
928 ok
= interfaces
.LoadFrom (name
);
930 if (!ok
) Verifier
.log
.Write ("error", String
.Format ("Unable to load interfaces from {0}.", name
), ImportanceLevel
.HIGH
);
932 enums
= new EnumCollection ();
933 ok
= enums
.LoadFrom (name
);
935 if (!ok
) Verifier
.log
.Write ("error", String
.Format ("Unable to load enums from {0}.", name
), ImportanceLevel
.HIGH
);
942 public override bool Equals (object o
)
944 bool res
= (o
is AssemblyStuff
);
946 AssemblyStuff that
= o
as AssemblyStuff
;
947 IEnumerator it
= comparers
.GetEnumerator ();
948 while ((res
|| !Verifier
.stopOnError
) && it
.MoveNext ()) {
949 Comparer compare
= it
.Current
as Comparer
;
950 res
&= compare (this, that
);
957 public static bool operator == (AssemblyStuff asm1
, AssemblyStuff asm2
)
959 return asm1
.Equals (asm2
);
962 public static bool operator != (AssemblyStuff asm1
, AssemblyStuff asm2
)
964 return !(asm1
== asm2
);
967 public override int GetHashCode ()
969 return classes
.GetHashCode () ^ interfaces
.GetHashCode ();
973 public override string ToString ()
977 res
= String
.Format ("Asssembly {0}, valid, {1} classes, {2} interfaces, {3} enums.",
978 name
, classes
.Count
, interfaces
.Count
, enums
.Count
);
980 res
= String
.Format ("Asssembly {0}, invalid.", name
);
990 ////////////////////////////////
992 ////////////////////////////////
994 public sealed class Compare
{
1001 public static bool Parameters (ParameterInfo
[] params1
, ParameterInfo
[] params2
)
1004 if (params1
.Length
!= params2
.Length
) {
1005 Verifier
.Log
.Write ("Parameter count mismatch.");
1009 int count
= params1
.Length
;
1011 for (int i
= 0; i
< count
&& res
; i
++) {
1012 if (params1
[i
].Name
!= params2
[i
].Name
) {
1013 Verifier
.Log
.Write ("error", String
.Format ("Parameters names mismatch {0}, {1}.", params1
[i
].Name
, params2
[i
].Name
));
1015 if (Verifier
.stopOnError
) break;
1018 Verifier
.Log
.Write ("parameter", params1
[i
].Name
);
1020 if (!Compare
.Types (params1
[i
].ParameterType
, params2
[i
].ParameterType
)) {
1021 Verifier
.Log
.Write ("error", String
.Format ("Parameters types mismatch {0}, {1}.", params1
[i
].ParameterType
, params2
[i
].ParameterType
));
1023 if (Verifier
.stopOnError
) break;
1027 if (Verifier
.checkOptionalFlags
) {
1028 if (params1
[i
].IsIn
!= params2
[i
].IsIn
) {
1029 Verifier
.Log
.Write ("error", "[in] mismatch.");
1031 if (Verifier
.stopOnError
) break;
1034 if (params1
[i
].IsOut
!= params2
[i
].IsOut
) {
1035 Verifier
.Log
.Write ("error", "[out] mismatch.");
1037 if (Verifier
.stopOnError
) break;
1040 if (params1
[i
].IsRetval
!= params2
[i
].IsRetval
) {
1041 Verifier
.Log
.Write ("error", "[ref] mismatch.");
1043 if (Verifier
.stopOnError
) break;
1046 if (params1
[i
].IsOptional
!= params2
[i
].IsOptional
) {
1047 Verifier
.Log
.Write ("error", "Optional flag mismatch.");
1049 if (Verifier
.stopOnError
) break;
1052 } // checkOptionalFlags
1062 public static bool Methods (MethodInfo mi1
, MethodInfo mi2
)
1066 Verifier
.Log
.Write ("error", String
.Format ("There is no such method {0}.", mi1
.Name
), ImportanceLevel
.MEDIUM
);
1071 Verifier
.Log
.Flush ();
1072 Verifier
.Log
.Write ("method", String
.Format ("{0}.", mi1
.Name
));
1077 ok
= Compare
.Types (mi1
.ReturnType
, mi2
.ReturnType
);
1080 Verifier
.Log
.Write ("error", "Return types mismatch.", ImportanceLevel
.MEDIUM
);
1081 if (Verifier
.stopOnError
) return res
;
1087 ok
= (mi1
.IsAbstract
== mi2
.IsAbstract
);
1090 expected
= (mi1
.IsAbstract
) ? "abstract" : "non-abstract";
1091 Verifier
.Log
.Write ("error", String
.Format ("Expected to be {0}.", expected
), ImportanceLevel
.MEDIUM
);
1092 if (Verifier
.stopOnError
) return res
;
1095 ok
= (mi1
.IsVirtual
== mi2
.IsVirtual
);
1098 expected
= (mi1
.IsVirtual
) ? "virtual" : "non-virtual";
1099 Verifier
.Log
.Write ("error", String
.Format ("Expected to be {0}.", expected
), ImportanceLevel
.MEDIUM
);
1100 if (Verifier
.stopOnError
) return res
;
1103 ok
= (mi1
.IsFinal
== mi2
.IsFinal
);
1106 expected
= (mi1
.IsFinal
) ? "final" : "overridable";
1107 Verifier
.Log
.Write ("error", String
.Format ("Expected to be {0}.", expected
), ImportanceLevel
.MEDIUM
);
1108 if (Verifier
.stopOnError
) return res
;
1113 // compare access modifiers
1115 ok
= (mi1
.IsPrivate
== mi2
.IsPrivate
);
1118 expected
= (mi1
.IsPublic
) ? "public" : "private";
1119 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1120 if (Verifier
.stopOnError
) return res
;
1124 ok
= (mi1
.IsFamily
== mi2
.IsFamily
);
1127 expected
= (mi1
.IsFamily
) ? "protected" : "!protected";
1128 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1129 if (Verifier
.stopOnError
) return res
;
1132 ok
= (mi1
.IsAssembly
== mi2
.IsAssembly
);
1135 expected
= (mi1
.IsAssembly
) ? "internal" : "!internal";
1136 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1137 if (Verifier
.stopOnError
) return res
;
1141 ok
= (mi1
.IsStatic
== mi2
.IsStatic
);
1144 expected
= (mi1
.IsStatic
) ? "static" : "instance";
1145 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1146 if (Verifier
.stopOnError
) return res
;
1153 ok
= Compare
.Parameters (mi1
.GetParameters (), mi2
.GetParameters ());
1155 if (!ok
&& Verifier
.stopOnError
) return res
;
1158 ok
= (mi1
.CallingConvention
== mi2
.CallingConvention
);
1161 Verifier
.Log
.Write ("error", "Calling conventions mismatch.", ImportanceLevel
.MEDIUM
);
1162 if (Verifier
.stopOnError
) return res
;
1172 public static bool Fields (FieldInfo fi1
, FieldInfo fi2
)
1175 Verifier
.Log
.Write ("error", String
.Format ("There is no such field {0}.", fi1
.Name
), ImportanceLevel
.MEDIUM
);
1183 Verifier
.Log
.Write ("field", String
.Format ("{0}.", fi1
.Name
));
1185 ok
= (fi1
.IsPrivate
== fi2
.IsPrivate
);
1188 expected
= (fi1
.IsPublic
) ? "public" : "private";
1189 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1190 if (Verifier
.stopOnError
) return res
;
1193 ok
= (fi1
.IsFamily
== fi2
.IsFamily
);
1196 expected
= (fi1
.IsFamily
) ? "protected" : "!protected";
1197 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1198 if (Verifier
.stopOnError
) return res
;
1201 ok
= (fi1
.IsAssembly
== fi2
.IsAssembly
);
1204 expected
= (fi1
.IsAssembly
) ? "internal" : "!internal";
1205 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1206 if (Verifier
.stopOnError
) return res
;
1209 ok
= (fi1
.IsInitOnly
== fi2
.IsInitOnly
);
1212 expected
= (fi1
.IsInitOnly
) ? "readonly" : "!readonly";
1213 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1214 if (Verifier
.stopOnError
) return res
;
1217 ok
= (fi1
.IsStatic
== fi2
.IsStatic
);
1220 expected
= (fi1
.IsStatic
) ? "static" : "instance";
1221 Verifier
.Log
.Write ("error", String
.Format ("Accessibility levels mismatch (expected [{0}]).", expected
), ImportanceLevel
.MEDIUM
);
1222 if (Verifier
.stopOnError
) return res
;
1230 public static bool Types (Type type1
, Type type2
)
1233 // simply calling type1.Equals (type2) won't work,
1234 // types are in different assemblies hence they have
1235 // different (fully-qualified) names.
1237 eqFlags
|= (type1
.IsAbstract
== type2
.IsAbstract
) ? 0 : 0x001;
1238 eqFlags
|= (type1
.IsClass
== type2
.IsClass
) ? 0 : 0x002;
1239 eqFlags
|= (type1
.IsValueType
== type2
.IsValueType
) ? 0 : 0x004;
1240 eqFlags
|= (type1
.IsPublic
== type2
.IsPublic
) ? 0 : 0x008;
1241 eqFlags
|= (type1
.IsSealed
== type2
.IsSealed
) ? 0 : 0x010;
1242 eqFlags
|= (type1
.IsEnum
== type2
.IsEnum
) ? 0 : 0x020;
1243 eqFlags
|= (type1
.IsPointer
== type2
.IsPointer
) ? 0 : 0x040;
1244 eqFlags
|= (type1
.IsPrimitive
== type2
.IsPrimitive
) ? 0 : 0x080;
1245 bool res
= (eqFlags
== 0);
1248 // TODO: convert flags into descriptive message.
1249 Verifier
.Log
.Write ("error", "Types mismatch (0x" + eqFlags
.ToString("X") + ").", ImportanceLevel
.HIGH
);
1255 ok
= (type1
.Attributes
& TypeAttributes
.BeforeFieldInit
) ==
1256 (type2
.Attributes
& TypeAttributes
.BeforeFieldInit
);
1258 Verifier
.Log
.Write ("error", "Types attributes mismatch: BeforeFieldInit.", ImportanceLevel
.HIGH
);
1262 ok
= (type1
.Attributes
& TypeAttributes
.ExplicitLayout
) ==
1263 (type2
.Attributes
& TypeAttributes
.ExplicitLayout
);
1265 Verifier
.Log
.Write ("error", "Types attributes mismatch: ExplicitLayout.", ImportanceLevel
.HIGH
);
1269 ok
= (type1
.Attributes
& TypeAttributes
.SequentialLayout
) ==
1270 (type2
.Attributes
& TypeAttributes
.SequentialLayout
);
1272 Verifier
.Log
.Write ("error", "Types attributes mismatch: SequentialLayout.", ImportanceLevel
.HIGH
);
1276 ok
= (type1
.Attributes
& TypeAttributes
.Serializable
) ==
1277 (type2
.Attributes
& TypeAttributes
.Serializable
);
1279 Verifier
.Log
.Write ("error", "Types attributes mismatch: Serializable.", ImportanceLevel
.HIGH
);
1291 ////////////////////////////////
1293 ////////////////////////////////
1295 public enum ImportanceLevel
: int {
1296 LOW
= 0, MEDIUM
, HIGH
1300 public interface ILogger
{
1302 void Write (string tag
, string msg
, ImportanceLevel importance
);
1303 void Write (string msg
, ImportanceLevel level
);
1304 void Write (string tag
, string msg
);
1305 void Write (string msg
);
1306 ImportanceLevel DefaultImportance {get; set;}
1312 public abstract class AbstractLogger
: ILogger
{
1313 private ImportanceLevel defImportance
= ImportanceLevel
.MEDIUM
;
1315 public abstract void Write (string tag
, string msg
, ImportanceLevel importance
);
1316 public abstract void Write (string msg
, ImportanceLevel level
);
1318 public virtual void Write (string tag
, string msg
)
1320 Write (tag
, msg
, DefaultImportance
);
1323 public virtual void Write (string msg
)
1325 Write (msg
, DefaultImportance
);
1328 public virtual ImportanceLevel DefaultImportance
{
1330 return defImportance
;
1333 defImportance
= value < ImportanceLevel
.LOW
1334 ? ImportanceLevel
.LOW
1335 : value > ImportanceLevel
.HIGH
1336 ? ImportanceLevel
.HIGH
1341 public abstract void Flush ();
1342 public abstract void Close ();
1348 public class TextLogger
: AbstractLogger
{
1350 private TextWriter writer
;
1352 public TextLogger (TextWriter writer
)
1355 throw new NullReferenceException ();
1357 this.writer
= writer
;
1360 private void DoWrite (string tag
, string msg
)
1362 if (tag
!= null && tag
.Length
> 0) {
1363 writer
.WriteLine ("[{0}]\t{1}", tag
, msg
);
1365 writer
.WriteLine ("\t\t" + msg
);
1369 public override void Write (string tag
, string msg
, ImportanceLevel importance
)
1371 int v
= Log
.VerboseLevel
;
1376 if (importance
>= ImportanceLevel
.HIGH
) {
1381 if (importance
>= ImportanceLevel
.MEDIUM
) {
1393 public override void Write (string msg
, ImportanceLevel importance
)
1395 Write (null, msg
, importance
);
1398 public override void Flush ()
1400 Console
.Out
.Flush ();
1403 public override void Close ()
1405 if (writer
!= Console
.Out
&& writer
!= Console
.Error
) {
1413 public sealed class Log
{
1415 private static int verbose
= 3;
1417 private ArrayList consumers
;
1419 public Log (bool useDefault
)
1421 consumers
= new ArrayList ();
1422 if (useDefault
) AddConsumer (new TextLogger (Console
.Out
));
1425 public Log () : this (true)
1430 public static int VerboseLevel
{
1435 verbose
= (value < 0)
1442 public void AddConsumer (ILogger consumer
)
1444 consumers
.Add (consumer
);
1448 public void Write (string tag
, string msg
, ImportanceLevel importance
)
1450 foreach (ILogger logger
in consumers
) {
1451 if (tag
== null || tag
== "") {
1452 logger
.Write (msg
, importance
);
1454 logger
.Write (tag
, msg
, importance
);
1459 public void Write (string msg
, ImportanceLevel importance
)
1461 Write (null, msg
, importance
);
1465 public void Write (string tag
, string msg
)
1467 foreach (ILogger logger
in consumers
) {
1468 if (tag
== null || tag
== "") {
1471 logger
.Write (tag
, msg
);
1476 public void Write (string msg
)
1482 public void Flush ()
1484 foreach (ILogger logger
in consumers
) {
1490 public void Close ()
1492 foreach (ILogger logger
in consumers
) {
1505 ////////////////////////////////
1507 ////////////////////////////////
1509 public class Verifier
{
1511 public static readonly Log log
= new Log ();
1512 public static bool stopOnError
= false;
1513 public static bool ignoreMissingTypes
= true;
1514 public static bool checkOptionalFlags
= true;
1516 private static readonly IList excluded
;
1520 excluded
= new ArrayList ();
1521 excluded
.Add ("<PrivateImplementationDetails>");
1529 public static Log Log
{
1535 public static IList Excluded
{
1543 public static void Main (String
[] args
)
1545 if (args
.Length
< 2) {
1546 Console
.WriteLine ("Usage: verifier assembly1 assembly2");
1548 string name1
= args
[0];
1549 string name2
= args
[1];
1553 AssemblyStuff asm1
= new AssemblyStuff (name1
);
1554 AssemblyStuff asm2
= new AssemblyStuff (name2
);
1557 Console
.WriteLine ("Unable to load assembly {0}.", name1
);
1558 Environment
.Exit (-1);
1563 Console
.WriteLine ("Unable to load assembly {0}.", name2
);
1564 Environment
.Exit (-1);
1569 ok
= (asm1
== asm2
);
1577 Console
.WriteLine ("--- not equal");
1578 Environment
.Exit (-1);