xamarin-macios/tests/xtro-sharpie/xtro-sanity/Sanitizer.cs

242 строки
7.8 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
namespace Extrospection {
class Sanitizer {
static readonly string [] Platforms = new [] { "iOS", "tvOS", "watchOS", "macOS" };
static bool IsEntry (string line)
{
return line.Length > 0 && line [0] == '!';
}
// Entries are correct if each line
// * is empty; or
// * starts with a '!' (entries); or
// * starts with a "#" (comments) except for
// * "#!" since it's a commented entry (and should not be committed)
static void CorrectEntries (List<string> entries, string filename)
{
foreach (var entry in entries) {
if (IsEntry (entry))
continue;
if (entry.Length == 0)
continue;
if (entry [0] != '#') {
Log ($"?bad-entry? '{entry}' in '{filename}'");
} else if (entry [1] == '!') {
Log ($"?bad-comment? '{entry}' in '{filename}'");
}
}
}
// Comments can be duplicated but not entries
static void UniqueEntries (List<string> entries, string filename)
{
for (int i = 0; i < entries.Count; i++) {
var entry = entries [i];
if (!IsEntry (entry))
continue;
for (int j = i + 1; j < entries.Count; j++) {
if (entry == entries [j])
Log ($"?dupe-entry? {entry} in '{filename}'");
}
}
}
// it's either common (for all/most) or platform specific - not both
static void NoDuplicateInCommonIgnores ()
{
foreach (var kvp in commons) {
var fx = kvp.Key;
var common = kvp.Value;
foreach (var platform in Platforms) {
var p = Path.Combine (directory, $"{platform}-{fx}.ignore");
if (!File.Exists (p))
continue;
foreach (var entry in File.ReadAllLines (p)) {
if (!IsEntry (entry))
continue;
if (!common.Contains (entry))
continue;
Log ($"?dupe-common? Entry '{entry}' in both 'common-{fx}.ignore' and '{Path.GetFileName (p)}' files");
}
}
}
}
// it's either something in our todo list or something we can ignore - not both
static void NoIgnoredTodo ()
{
foreach (var file in Directory.GetFiles (directory, "*.todo")) {
var last = file.LastIndexOf ('-');
var fx = file.Substring (last + 1, file.Length - last - 6);
// check if it's in common or in the same platform
if (commons.TryGetValue (fx, out var common)) {
foreach (var entry in File.ReadAllLines (file)) {
if (!IsEntry (entry))
continue;
if (common.Contains (entry))
Log ($"?dupe-todo? Entry '{entry}' in both 'common-{fx}.ignore' and '{Path.GetFileName (file)}' files");
}
}
var platform = Path.ChangeExtension (file, ".ignore");
if (File.Exists (platform)) {
var specific = new List<string> (File.ReadAllLines (platform));
foreach (var entry in File.ReadAllLines (file)) {
if (!IsEntry (entry))
continue;
if (specific.Contains (entry))
Log ($"?dupe-todo? Entry '{entry}' in both '{Path.GetFileName (platform)}' and '{Path.GetFileName (file)}' files");
}
}
}
}
static void NoFixedTodo ()
{
foreach (var file in Directory.GetFiles (directory, "*.todo")) {
var last = file.LastIndexOf ('-');
var fx = file.Substring (last + 1, file.Length - last - 6);
var raw = Path.ChangeExtension (file, ".raw");
if (File.Exists (raw)) {
var specific = new List<string> (File.ReadAllLines (raw));
foreach (var entry in File.ReadAllLines (file)) {
if (!IsEntry (entry))
continue;
if (!specific.Contains (entry))
Log ($"?fixed-todo? Entry '{entry}' in '{Path.GetFileName (file)}' is not found in corresponding '{Path.GetFileName (raw)}' file");
}
} else {
// no .raw then everything is fixed
foreach (var entry in File.ReadAllLines (file)) {
if (!IsEntry (entry))
continue;
Log ($"?fixed-todo? Entry '{entry}' in '{Path.GetFileName (file)}' might be fixed since there's no corresponding '{Path.GetFileName (raw)}' file");
}
}
}
}
static string directory;
static Dictionary<string, List<string>> commons = new Dictionary<string, List<string>> ();
static int count;
public static void Log (string s)
{
Console.WriteLine (s);
count++;
}
public static int Main (string [] args)
{
directory = args.Length == 0 ? "." : args [0];
// cache stuff
foreach (var file in Directory.GetFiles (directory, "common-*.ignore")) {
var path = Path.GetFileName (file);
var fx = path.Substring (7, path.Length - 14);
var common = new List<string> (File.ReadAllLines (file));
commons.Add (fx, common);
}
// *.ignore validations
// basic sanity for ignores
foreach (var kvp in commons) {
var fx = kvp.Key;
var common = kvp.Value;
CorrectEntries (common, $"common-{fx}.ignore");
}
foreach (var file in Directory.GetFiles (directory, "*.ignore")) {
var filename = Path.GetFileName (file);
// already processed from cache - don't reload them
if (filename.StartsWith ("common-", StringComparison.Ordinal))
continue;
var entries = new List<string> (File.ReadAllLines (file));
CorrectEntries (entries, filename);
}
// uniqueness - check that each .ignore file has no duplicate
foreach (var kvp in commons) {
var fx = kvp.Key;
var common = kvp.Value;
UniqueEntries (common, $"common-{fx}.ignore");
}
foreach (var file in Directory.GetFiles (directory, "*.ignore")) {
var entries = new List<string> (File.ReadAllLines (file));
UniqueEntries (entries, Path.GetFileName (file));
}
// platform specific ignore entries should *not* be duplicated in common-*.ignore
NoDuplicateInCommonIgnores ();
// TODO entries present in all platforms .ignore files should be moved to common
// ignored entries should all exists in the unfiltered .unclassified (raw)
// * common-{fx}.ignored must be part of _at least_ one *-{fx}.raw file
foreach (var kvp in commons) {
var fx = kvp.Key;
var common = kvp.Value;
//ExistingCommonEntries (common, $"common-{fx}.ignore");
List<string> [] raws = new List<string> [Platforms.Length];
for (int i=0; i < raws.Length; i++) {
var fname = Path.Combine (directory, $"{Platforms[i]}-{fx}.raw");
if (File.Exists (fname))
raws [i] = new List<string> (File.ReadAllLines (fname));
else
raws [i] = new List<string> ();
}
foreach (var entry in common) {
if (!entry.StartsWith ("!", StringComparison.Ordinal))
continue;
bool found = false;
foreach (var platform in raws) {
found = platform.Contains (entry);
if (found)
break;
}
if (!found)
Log ($"?unknown-entry? {entry} in 'common-{fx}.ignore'");
}
}
// * a platform ignore must existing in it's corresponding raw file
foreach (var file in Directory.GetFiles (directory, "*.ignore")) {
var shortname = Path.GetFileName (file);
if (shortname.StartsWith ("common-", StringComparison.Ordinal))
continue;
// FIXME temporary hack for old data files
if (!shortname.Contains ("-"))
continue;
var rawfile = Path.ChangeExtension (file, ".raw");
var raws = new List<string> (File.ReadAllLines (rawfile));
foreach (var entry in File.ReadAllLines (file)) {
if (!entry.StartsWith ("!", StringComparison.Ordinal))
continue;
if (raws.Contains (entry))
continue;
Log ($"?unknown-entry? {entry} in '{shortname}'");
}
}
// *.todo validations
// entries in .todo files should *not* be present in *.ignore files
NoIgnoredTodo ();
// entries in .todo should be found in .raw files - else it's likely fixed (and out of date)
NoFixedTodo ();
if (count == 0)
Console.WriteLine ("Sanity check passed");
else
Console.WriteLine ($"Sanity check failed ({count})");
// useful when updating stuff locally - we report but we don't fail
return Environment.GetEnvironmentVariable ("XTRO_SANITY_SKIP") == "1" ? 0 : count;
}
}
}