using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace StellaOps.Reachability.FixtureTests.PatchOracle;
///
/// Loads patch-oracle definitions from fixture files.
///
public sealed class PatchOracleLoader
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
private readonly string _fixtureRoot;
public PatchOracleLoader(string fixtureRoot)
{
_fixtureRoot = fixtureRoot ?? throw new ArgumentNullException(nameof(fixtureRoot));
}
///
/// Loads the oracle index from INDEX.json.
///
public PatchOracleIndex LoadIndex()
{
var indexPath = Path.Combine(_fixtureRoot, "INDEX.json");
if (!File.Exists(indexPath))
{
throw new FileNotFoundException($"Patch-oracle INDEX.json not found at {indexPath}");
}
var json = File.ReadAllText(indexPath);
return JsonSerializer.Deserialize(json, JsonOptions)
?? throw new InvalidOperationException("Failed to deserialize patch-oracle index");
}
///
/// Loads an oracle definition by its ID.
///
public PatchOracleDefinition LoadOracle(string oracleId)
{
var index = LoadIndex();
var entry = index.Oracles
.FirstOrDefault(o => string.Equals(o.Id, oracleId, StringComparison.Ordinal))
?? throw new KeyNotFoundException($"Oracle '{oracleId}' not found in index");
return LoadOracleFromPath(entry.Path);
}
///
/// Loads an oracle definition from a relative path.
///
public PatchOracleDefinition LoadOracleFromPath(string relativePath)
{
var fullPath = Path.Combine(_fixtureRoot, relativePath);
if (!File.Exists(fullPath))
{
throw new FileNotFoundException($"Oracle file not found at {fullPath}");
}
var json = File.ReadAllText(fullPath);
return JsonSerializer.Deserialize(json, JsonOptions)
?? throw new InvalidOperationException($"Failed to deserialize oracle from {fullPath}");
}
///
/// Loads all oracles for a specific case.
///
public IEnumerable LoadOraclesForCase(string caseRef)
{
var index = LoadIndex();
foreach (var entry in index.Oracles.Where(o => string.Equals(o.CaseRef, caseRef, StringComparison.Ordinal)))
{
yield return LoadOracleFromPath(entry.Path);
}
}
///
/// Loads all available oracles.
///
public IEnumerable LoadAllOracles()
{
var index = LoadIndex();
foreach (var entry in index.Oracles)
{
yield return LoadOracleFromPath(entry.Path);
}
}
///
/// Enumerates all oracle entries without loading full definitions.
///
public IEnumerable EnumerateOracles()
{
var index = LoadIndex();
return index.Oracles;
}
///
/// Checks if the oracle index exists.
///
public bool IndexExists()
{
return File.Exists(Path.Combine(_fixtureRoot, "INDEX.json"));
}
}