private static void VerifyDifferentRegistries(OrToolsSatGeneratedSyntaxTreeRegistry previousRegistry , OrToolsSatGeneratedSyntaxTreeRegistry currentRegistry) { { bool DirectoryExists(OrToolsSatGeneratedSyntaxTreeRegistry x) => Directory.Exists(x.OutputDirectory); // Do some quick verification of each Registry. previousRegistry = previousRegistry.AssertNotNull().AssertNotEmpty().AssertTrue(DirectoryExists); currentRegistry = currentRegistry.AssertNotNull().AssertNotEmpty().AssertTrue(DirectoryExists); } // Should always Not be the Same. previousRegistry.AssertNotSame(currentRegistry); var previousKeys = previousRegistry.SelectMany(x => x.GeneratedAssetKeys).AssertNotEmpty().ToList().AssertTrue(x => x.Any()); var currentKeys = currentRegistry.SelectMany(x => x.GeneratedAssetKeys).AssertNotEmpty().ToList().AssertTrue(x => x.Any()); { // None of the Second Registry Generated Keys should exist in the First Registry. void KeysDoesNotContain(IEnumerable <Guid> collection, Guid y) => collection.AssertDoesNotContain(x => x == y); // The two sets of Generated Code ought not to overlap whatsoever. currentKeys.ForEach(x => KeysDoesNotContain(previousKeys, x)); previousKeys.ForEach(x => KeysDoesNotContain(currentKeys, x)); } { // Newly Generated Code will exist, should also be able to verify this. void FileExists(string path) => path.AssertFileExists(); currentKeys.Select(x => Path.Combine(currentRegistry.OutputDirectory, x.RenderGeneratedFileName())).ToList().ForEach(FileExists); } { // Previously Generated Code will have been Purged, should be able to verify this. void FileDoesNotExist(string path) => path.AssertFileDoesNotExist(); previousKeys.Select(x => Path.Combine(previousRegistry.OutputDirectory, x.RenderGeneratedFileName())).ToList().ForEach(FileDoesNotExist); } }
/// <summary> /// We need to Evaluate a further and much more in depth Purge opportunity given the /// <paramref name="registry"/> and set of <paramref name="renderedCompilationUnits"/>. /// </summary> /// <param name="registry"></param> /// <param name="renderedCompilationUnits"></param> /// <returns></returns> private bool TryEvaluateCompilationUnits(OrToolsSatGeneratedSyntaxTreeRegistry registry , IRenderedCompilationUnitDictionary renderedCompilationUnits) { // Pretty sure we want to do an Ordinal comparison here. But this is a function of the Invocation. bool StringEquals(string a, string b, StringComparison comparisonType) => !(a == null || b == null) && string.Equals(a.Trim(), b.Trim(), comparisonType); bool TryDecomposeCompilationUnitSyntaxPair(CompilationUnitSyntaxPair pair , out string generatedCode) => !IsNullOrEmpty(generatedCode = pair.Value); // This is a bit involved, but this gains us sufficient accounting of Generated Code. bool ThereAreCodeGenerationInconsistencies(GeneratedSyntaxTreeDescriptor _) { var outputDirectory = registry.OutputDirectory; var filePaths = Directory.EnumerateFiles(outputDirectory, $"*{g}{cs}", TopDirectoryOnly); // Obtain any Previously Existing Baseline Generated Code in the form of a Stream Factory. var streamFactories = filePaths.Select(filePath => (Func <Stream>)( () => File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read) )); // Which has the added benefit of deferring Stream operations until we absolutely need them. foreach (var streamFactory in streamFactories) { string baselineGeneratedCode; /* And which also defers the actual delegate formation given the nature of the LINQ * provider. Performance may vary from OS to OS, from Run-time to Run-time. */ using (var fs = streamFactory.Invoke()) { // Do this operation Once and Only Once for the breadth of the candidate set of Generated Code. using (var sr = new StreamReader(fs)) { baselineGeneratedCode = sr.ReadToEndAsync().Result; } } // Continue when Code Generation Consistency checks can be verified. if (renderedCompilationUnits.Any( pair => TryDecomposeCompilationUnitSyntaxPair(pair, out var x) && StringEquals(x, baselineGeneratedCode, Ordinal))) { continue; } if (DebugMessagesSwitch) { Writer.WriteLine("Generated code inconsistencies discovered, purge required."); } // Otherwise, break, we know the set to be Inconsistent, i.e. re-Generation required. return(true); } if (DebugMessagesSwitch) { Writer.WriteLine("Generated code found to be consistent, purge not required."); } // If everything checked out, All Consistent, then we are Clear to Bypass Code Generation. return(false); } var areNonePreviouslyGenerated = !registry.SelectMany(x => x.GeneratedAssetKeys).Any(); var areObviouslyDifferent = registry.SelectMany(x => x.GeneratedAssetKeys).Count() != renderedCompilationUnits.Count; var thereAreCodeGenerationInconsistencies = registry.Any(ThereAreCodeGenerationInconsistencies); var shouldPurge = areNonePreviouslyGenerated || areObviouslyDifferent || thereAreCodeGenerationInconsistencies; registry.PurgeWhere(_ => shouldPurge); return(shouldPurge); }