diff --git a/docs/reference.md b/docs/reference.md index 4a78518..366686d 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -322,6 +322,7 @@ Public error classes: - `FixtureKit::FixtureDefinitionNotFound` - `FixtureKit::RunnerAlreadyStartedError` - `FixtureKit::CircularFixtureInheritance` +- `FixtureKit::MissingCoderDataError` ## Requirements diff --git a/lib/fixture_kit.rb b/lib/fixture_kit.rb index 7caf094..e6458f7 100644 --- a/lib/fixture_kit.rb +++ b/lib/fixture_kit.rb @@ -9,6 +9,7 @@ class CacheMissingError < Error; end class FixtureDefinitionNotFound < Error; end class RunnerAlreadyStartedError < Error; end class CircularFixtureInheritance < Error; end + class MissingCoderDataError < Error; end autoload :VERSION, File.expand_path("fixture_kit/version", __dir__) autoload :Configuration, File.expand_path("fixture_kit/configuration", __dir__) diff --git a/lib/fixture_kit/memory_cache.rb b/lib/fixture_kit/memory_cache.rb index dd9aa1c..61f166e 100644 --- a/lib/fixture_kit/memory_cache.rb +++ b/lib/fixture_kit/memory_cache.rb @@ -11,7 +11,13 @@ def initialize(data:, exposed:) end def data_for(coder_class) - data.fetch(coder_class) + data.fetch(coder_class) do + raise MissingCoderDataError, + "The fixture cache has no data for #{coder_class}. This usually means " \ + "the cache was written before #{coder_class} was registered as a coder. " \ + "Regenerate the fixture cache so it includes this coder (clear the cache " \ + "directory, or run without FIXTURE_KIT_PRESERVE_CACHE=1)." + end end end end diff --git a/spec/unit/memory_cache_spec.rb b/spec/unit/memory_cache_spec.rb index 3fb916a..4a1a4b7 100644 --- a/spec/unit/memory_cache_spec.rb +++ b/spec/unit/memory_cache_spec.rb @@ -20,4 +20,28 @@ expect(cache).to be_frozen end end + + describe "#data_for" do + it "returns the data stored for a coder class" do + cache = described_class.new( + data: { FixtureKit::ActiveRecordCoder => { "User" => "SQL" } }, + exposed: {} + ) + + expect(cache.data_for(FixtureKit::ActiveRecordCoder)).to eq({ "User" => "SQL" }) + end + + it "raises an actionable error when the cache predates a coder" do + # A cache written before this coder was registered has no entry for it. + # Rather than an opaque KeyError, callers should learn the cache is stale + # and how to fix it — naming the coder and pointing to regeneration. + cache = described_class.new(data: {}, exposed: {}) + + expect { cache.data_for(FixtureKit::ActiveRecordCoder) } + .to raise_error(FixtureKit::MissingCoderDataError) do |error| + expect(error.message).to include("FixtureKit::ActiveRecordCoder") + expect(error.message).to match(/regenerate/i) + end + end + end end