< Summary

Information
Class: ValidateLib.TableCompatibility.CompatibilityChecker
Assembly: validatelib.dll
File(s): C:\skola_karlovka\RP\code\csv-validator\CSV_Validator\ValidateLib\TableCompatibility\CompatibilityChecker.cs
Line coverage
90%
Covered lines: 75
Uncovered lines: 8
Coverable lines: 83
Total lines: 194
Line coverage: 90.3%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

C:\skola_karlovka\RP\code\csv-validator\CSV_Validator\ValidateLib\TableCompatibility\CompatibilityChecker.cs

#LineLine coverage
 1using ValidateLib.ErrorsAndWarnings.Errors;
 2using ValidateLib.ErrorsAndWarnings.Errors.ValidationErrors;
 3using ValidateLib.Metadata.Descriptors;
 4using ValidateLib.Metadata.Embedded;
 5using ValidateLib.Results;
 6
 7namespace ValidateLib.TableCompatibility
 8{
 9    /// <summary>
 10    /// Provides utilities for checking compatibilities of table descriptors and
 11    /// table schemes. Needed for tabular data validation.
 12    /// </summary>
 13    public class CompatibilityChecker : ICompatibilityChecker
 14    {
 15        public int _conflictingColumnNumber;
 16        /// <summary>
 17        /// Implements : https://www.w3.org/TR/2015/REC-tabular-metadata-20151217/#schema-compatibility
 18        /// </summary>
 19        /// <param name="schema1"> first schema to be checked</param>
 20        /// <param name="schema2"> second schema to be checked</param>
 21        /// <returns> True if the schemes are compatible </returns>
 22
 23        public void CheckSchemesCompatible(TableGroupDescriptor tableGroup, ITableGroupValidationDetail validationDetail
 24        {
 125            for (int i = 0; i < tableGroup.tables!._value!.Count; i++)
 26            {
 127                var table = tableGroup.tables!._value![i];
 28                try
 29                {
 130                    using (var fs = table._fileWrapper!.OpenNewFileStream())
 31                    {
 132                        var emMetadataExtractor = new EmbeddedMetadataExtractor(table._flags!);
 133                        var embeddedMetadata = emMetadataExtractor.extractEmbeddedMetadataTableDescriptor(fs!, table.dia
 34
 135                        if (!AreTableDescriptionsCompatible(table, embeddedMetadata))
 36                        {
 137                            validationDetails.TableValidationDetails[i].Errors.Add
 138                                (
 139                                ErrorFactory.GetTableSchemesNotCompatibleError
 140                                    (
 141                                        table.url!._value!,
 142                                        _conflictingColumnNumber
 143                                    )
 144                                );
 45                        }
 146                    }
 147                }
 148                catch (Exception ex)
 49                {
 150                    ErrorFactory.ThrowRemoteFileResoltuionError(table.url!._value!, ex.Message);
 051                }
 52
 53            }
 154        }
 55        public bool AreSchemaDescriptorsCompatible(SchemaDescriptor schema1, SchemaDescriptor schema2)
 56        {
 157            int schema1NonVirtColumnsCount = GetNumberOfNonVirutalColumns(schema1);
 158            int schema2NonVirtColumnsCount = GetNumberOfNonVirutalColumns(schema2);
 159            if (schema1NonVirtColumnsCount != schema2NonVirtColumnsCount)
 60            {
 161                _conflictingColumnNumber = Math.Max(schema1NonVirtColumnsCount, schema2NonVirtColumnsCount);
 162                return false;
 63            }
 64
 65
 166            if (schema1NonVirtColumnsCount > 0)
 67            {
 168                for (int i = 0; i < schema1NonVirtColumnsCount; i++)
 69                {
 170                    ColumnDescriptor column1 = schema1.columns!._value![i];
 171                    ColumnDescriptor column2 = schema2.columns!._value![i];
 172                    _conflictingColumnNumber = i + 1;
 173                    if (column1!._virtual!._value && !column2!._virtual!._value)
 074                        return false;
 175                    if (column2._virtual!._value! && !column1._virtual._value)
 076                        return false;
 177                    if (!AreTwoNonVirtualColumnsCompatible(schema1.columns._value[i], schema2.columns._value[i]))
 178                        return false; ;
 79                }
 80            }
 81
 182            return true;
 83        }
 84
 85        private static bool AreTwoNonVirtualColumnsCompatible(ColumnDescriptor column1, ColumnDescriptor column2)
 86        {
 87            // First case
 188            if (column1.name is null && column1.titles is null)
 089                return true;
 190            if (column2.name is null && column2.titles is null)
 091                return true;
 92
 93            // Second case
 94
 195            if (column1.name is not null && column2.name is not null)
 96            {
 197                if (column1.name._value == column2.name._value)
 198                    return true;
 99            }
 100
 101            // third case
 1102            return AreTheTitlesIntersecting(column1, column2);
 103
 104            // fourth case not considered because we are validating
 105
 106        }
 107
 108        private static bool AreTheTitlesIntersecting(ColumnDescriptor column1, ColumnDescriptor column2)
 109        {
 1110            if (!(column1.titles is not null && column1.titles is not null))
 1111                return false;
 112
 1113            Dictionary<string, string[]> titles1 = column1.titles!._value!;
 1114            Dictionary<string, string[]> titles2 = column2.titles!._value!;
 115
 1116            foreach (var keyValuePar in titles1)
 117            {
 118
 1119                if (keyValuePar.Key == "und")
 120                {
 1121                    foreach (var keyValuePar2 in titles2)
 122                    {
 1123                        if (HasNonEmptyCaseSensitiveIntersection(keyValuePar.Value, keyValuePar2.Value))
 1124                            return true;
 125                    }
 126                }
 127                else
 128                {
 129                    // TODO maybe some BCP truncation?
 1130                    if (titles2.ContainsKey(keyValuePar.Key))
 131                    {
 1132                        if (HasNonEmptyCaseSensitiveIntersection(keyValuePar.Value, titles2[keyValuePar.Key]))
 1133                            return true;
 134                    }
 1135                    if (titles2.ContainsKey("und"))
 136                    {
 1137                        if (HasNonEmptyCaseSensitiveIntersection(keyValuePar.Value, titles2["und"]))
 1138                            return true;
 139                    }
 140
 141                }
 142            }
 1143            return false;
 1144        }
 145
 146        static bool HasNonEmptyCaseSensitiveIntersection(string[] array1, string[] array2)
 147        {
 148            // Convert both arrays to HashSet for faster lookups
 1149            HashSet<string> set1 = new HashSet<string>(array1);
 1150            HashSet<string> set2 = new HashSet<string>(array2);
 151
 152            // Check if there is any common element in both sets (case-sensitive)
 1153            return set1.Intersect(set2, StringComparer.Ordinal).Any();
 154        }
 155
 156        /// <summary>
 157        /// Checks whether two table desciptors are compatible.
 158        /// Implements <see href="https://www.w3.org/TR/2015/REC-tabular-metadata-20151217/#table-description-compatibil
 159        /// </summary>
 160        /// <returns> true if they are compatible, false otherwise.</returns>
 161        public bool AreTableDescriptionsCompatible(TableDescriptor table1, TableDescriptor table2)
 162        {
 1163            if (table1.url is null || table2.url is null)
 0164                throw new ArgumentException("Required property missing!");
 165
 1166            if (table1.url._value != table2.url._value)
 1167                return false;
 168
 1169            if (table1.tableSchema is not null && table2.tableSchema is null)
 0170                return true;
 171
 1172            if (table2.tableSchema is not null && table1.tableSchema is null)
 1173                return true;
 174
 1175            if (table1.tableSchema is null && table2.tableSchema is null)
 0176                return true;
 177
 1178            return AreSchemaDescriptorsCompatible(table1.tableSchema!._value!, table2.tableSchema!._value!);
 179        }
 180
 181        public static int GetNumberOfNonVirutalColumns(SchemaDescriptor schema)
 182        {
 1183            if (schema.columns is null || schema.columns._value is null)
 1184                return 0;
 1185            int count = 0;
 1186            foreach (var column in schema.columns._value)
 187            {
 1188                if (!column._virtual!._value)
 1189                    count++;
 190            }
 1191            return count;
 192        }
 193    }
 194}