Merge pull request #4255 from MikeMcQuaid/fix-cache
linkage_cache: cache input data and not results.
This commit is contained in:
commit
63f8455ed3
@ -67,9 +67,7 @@ module FormulaCellarChecks
|
|||||||
keg = Keg.new(formula.prefix)
|
keg = Keg.new(formula.prefix)
|
||||||
|
|
||||||
CacheStoreDatabase.use(:linkage) do |db|
|
CacheStoreDatabase.use(:linkage) do |db|
|
||||||
checker = LinkageChecker.new(
|
checker = LinkageChecker.new(keg, formula, cache_db: db)
|
||||||
keg, formula, cache_db: db, use_cache: !ENV["HOMEBREW_LINKAGE_CACHE"].nil?
|
|
||||||
)
|
|
||||||
next unless checker.broken_library_linkage?
|
next unless checker.broken_library_linkage?
|
||||||
|
|
||||||
output = <<~EOS
|
output = <<~EOS
|
||||||
|
|||||||
@ -1537,9 +1537,7 @@ class Formula
|
|||||||
return [] unless keg
|
return [] unless keg
|
||||||
|
|
||||||
undeclared_deps = CacheStoreDatabase.use(:linkage) do |db|
|
undeclared_deps = CacheStoreDatabase.use(:linkage) do |db|
|
||||||
linkage_checker = LinkageChecker.new(
|
linkage_checker = LinkageChecker.new(keg, self, cache_db: db)
|
||||||
keg, self, cache_db: db, use_cache: !ENV["HOMEBREW_LINKAGE_CACHE"].nil?
|
|
||||||
)
|
|
||||||
linkage_checker.undeclared_deps.map { |n| Dependency.new(n) }
|
linkage_checker.undeclared_deps.map { |n| Dependency.new(n) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -604,17 +604,19 @@ class FormulaInstaller
|
|||||||
post_install
|
post_install
|
||||||
end
|
end
|
||||||
|
|
||||||
caveats
|
|
||||||
|
|
||||||
ohai "Summary" if verbose? || show_summary_heading?
|
|
||||||
puts summary
|
|
||||||
|
|
||||||
# Updates the cache for a particular formula after doing an install
|
# Updates the cache for a particular formula after doing an install
|
||||||
CacheStoreDatabase.use(:linkage) do |db|
|
CacheStoreDatabase.use(:linkage) do |db|
|
||||||
break unless db.created?
|
break unless db.created?
|
||||||
LinkageChecker.new(keg, formula, cache_db: db)
|
LinkageChecker.new(keg, formula, cache_db: db)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Update tab with actual runtime dependencies
|
||||||
|
tab = Tab.for_keg(keg)
|
||||||
|
Tab.clear_cache
|
||||||
|
tab.runtime_dependencies =
|
||||||
|
formula.runtime_dependencies(read_from_tab: false)
|
||||||
|
tab.write
|
||||||
|
|
||||||
# let's reset Utils.git_available? if we just installed git
|
# let's reset Utils.git_available? if we just installed git
|
||||||
Utils.clear_git_available_cache if formula.name == "git"
|
Utils.clear_git_available_cache if formula.name == "git"
|
||||||
|
|
||||||
@ -623,6 +625,11 @@ class FormulaInstaller
|
|||||||
!DevelopmentTools.curl_handles_most_https_certificates?
|
!DevelopmentTools.curl_handles_most_https_certificates?
|
||||||
ENV["HOMEBREW_CURL"] = formula.opt_bin/"curl"
|
ENV["HOMEBREW_CURL"] = formula.opt_bin/"curl"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
caveats
|
||||||
|
|
||||||
|
ohai "Summary" if verbose? || show_summary_heading?
|
||||||
|
puts summary
|
||||||
ensure
|
ensure
|
||||||
unlock
|
unlock
|
||||||
end
|
end
|
||||||
|
|||||||
@ -18,106 +18,55 @@ class LinkageCacheStore < CacheStore
|
|||||||
#
|
#
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def keg_exists?
|
def keg_exists?
|
||||||
!database.get(keg_name).nil?
|
!database.get(@keg_name).nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Inserts dylib-related information into the cache if it does not exist or
|
# Inserts dylib-related information into the cache if it does not exist or
|
||||||
# updates data into the linkage cache if it does exist
|
# updates data into the linkage cache if it does exist
|
||||||
#
|
#
|
||||||
# @param [Hash] array_values: hash containing KVPs of { :type => Array | Set }
|
|
||||||
# @param [Hash] hash_values: hash containing KVPs of { :type => Hash }
|
# @param [Hash] hash_values: hash containing KVPs of { :type => Hash }
|
||||||
# @param [Array[Hash]] values
|
|
||||||
# @raise [TypeError] error if the values are not `Arary`, `Set`, or `Hash`
|
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def update!(array_values: {}, hash_values: {}, **values)
|
def update!(hash_values)
|
||||||
values.each do |key, value|
|
hash_values.each_key do |type|
|
||||||
if value.is_a?(Hash)
|
next if HASH_LINKAGE_TYPES.include?(type)
|
||||||
hash_values[key] = value
|
|
||||||
elsif value.is_a?(Array) || value.is_a?(Set)
|
|
||||||
array_values[key] = value
|
|
||||||
else
|
|
||||||
raise TypeError, <<~EOS
|
raise TypeError, <<~EOS
|
||||||
Can't store types that are not `Array`, `Set` or `Hash` in the
|
Can't update types that are not defined for the linkage store
|
||||||
linkage store.
|
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
database.set keg_name, ruby_hash_to_json_string(
|
database.set @keg_name, ruby_hash_to_json_string(hash_values)
|
||||||
array_values: format_array_values(array_values),
|
|
||||||
hash_values: format_hash_values(hash_values),
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param [Symbol] the type to fetch from the `LinkageCacheStore`
|
# @param [Symbol] the type to fetch from the `LinkageCacheStore`
|
||||||
# @raise [TypeError] error if the type is not in `HASH_LINKAGE_TYPES` or
|
# @raise [TypeError] error if the type is not in `HASH_LINKAGE_TYPES`
|
||||||
# `ARRAY_LINKAGE_TYPES`
|
# @return [Hash]
|
||||||
# @return [Hash | Array]
|
|
||||||
def fetch_type(type)
|
def fetch_type(type)
|
||||||
if HASH_LINKAGE_TYPES.include?(type)
|
unless HASH_LINKAGE_TYPES.include?(type)
|
||||||
fetch_hash_values(type)
|
|
||||||
elsif ARRAY_LINKAGE_TYPES.include?(type)
|
|
||||||
fetch_array_values(type)
|
|
||||||
else
|
|
||||||
raise TypeError, <<~EOS
|
raise TypeError, <<~EOS
|
||||||
Can't fetch types that are not defined for the linkage store
|
Can't fetch types that are not defined for the linkage store
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return {} unless keg_exists?
|
||||||
|
|
||||||
|
fetch_hash_values(type)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def flush_cache!
|
def flush_cache!
|
||||||
database.delete(keg_name)
|
database.delete(@keg_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
ARRAY_LINKAGE_TYPES = [
|
HASH_LINKAGE_TYPES = [:keg_files_dylibs].freeze
|
||||||
:system_dylibs, :variable_dylibs, :broken_dylibs, :indirect_deps,
|
|
||||||
:undeclared_deps, :unnecessary_deps
|
|
||||||
].freeze
|
|
||||||
HASH_LINKAGE_TYPES = [:brewed_dylibs, :reverse_links, :broken_deps].freeze
|
|
||||||
|
|
||||||
# @return [String] the key to lookup items in the `CacheStore`
|
|
||||||
attr_reader :keg_name
|
|
||||||
|
|
||||||
# @param [Symbol] the type to fetch from the `LinkageCacheStore`
|
|
||||||
# @return [Array]
|
|
||||||
def fetch_array_values(type)
|
|
||||||
keg_cache = database.get(keg_name)
|
|
||||||
return [] unless keg_cache
|
|
||||||
json_string_to_ruby_hash(keg_cache)["array_values"][type.to_s]
|
|
||||||
end
|
|
||||||
|
|
||||||
# @param [Symbol] type
|
# @param [Symbol] type
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def fetch_hash_values(type)
|
def fetch_hash_values(type)
|
||||||
keg_cache = database.get(keg_name)
|
keg_cache = database.get(@keg_name)
|
||||||
return {} unless keg_cache
|
return {} unless keg_cache
|
||||||
json_string_to_ruby_hash(keg_cache)["hash_values"][type.to_s]
|
json_string_to_ruby_hash(keg_cache)[type.to_s]
|
||||||
end
|
|
||||||
|
|
||||||
# Formats the linkage data for `array_values` into a kind which can be parsed
|
|
||||||
# by the `json_string_to_ruby_hash` method. Internally converts ruby `Set`s to
|
|
||||||
# `Array`s
|
|
||||||
#
|
|
||||||
# @param [Hash]
|
|
||||||
# @return [String]
|
|
||||||
def format_array_values(hash)
|
|
||||||
hash.each_with_object({}) { |(k, v), h| h[k] = v.to_a }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Formats the linkage data for `hash_values` into a kind which can be parsed
|
|
||||||
# by the `json_string_to_ruby_hash` method. Converts ruby `Set`s to `Array`s,
|
|
||||||
# and converts ruby `Pathname`s to `String`s
|
|
||||||
#
|
|
||||||
# @param [Hash]
|
|
||||||
# @return [String]
|
|
||||||
def format_hash_values(hash)
|
|
||||||
hash.each_with_object({}) do |(outer_key, outer_values), outer_hash|
|
|
||||||
outer_hash[outer_key] = outer_values.each_with_object({}) do |(k, v), h|
|
|
||||||
h[k] = v.to_a.map(&:to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,118 +3,99 @@ require "formula"
|
|||||||
require "linkage_cache_store"
|
require "linkage_cache_store"
|
||||||
|
|
||||||
class LinkageChecker
|
class LinkageChecker
|
||||||
def initialize(keg, formula = nil, use_cache: false, cache_db:)
|
attr_reader :undeclared_deps
|
||||||
|
|
||||||
|
def initialize(keg, formula = nil, cache_db:,
|
||||||
|
use_cache: !ENV["HOMEBREW_LINKAGE_CACHE"].nil?)
|
||||||
@keg = keg
|
@keg = keg
|
||||||
@formula = formula || resolve_formula(keg)
|
@formula = formula || resolve_formula(keg)
|
||||||
|
@store = LinkageCacheStore.new(keg.name, cache_db) if use_cache
|
||||||
|
|
||||||
if use_cache
|
@system_dylibs = Set.new
|
||||||
@store = LinkageCacheStore.new(keg.name, cache_db)
|
@broken_dylibs = Set.new
|
||||||
flush_cache_and_check_dylibs unless @store.keg_exists?
|
@variable_dylibs = Set.new
|
||||||
else
|
@brewed_dylibs = Hash.new { |h, k| h[k] = Set.new }
|
||||||
flush_cache_and_check_dylibs
|
@reverse_links = Hash.new { |h, k| h[k] = Set.new }
|
||||||
end
|
@broken_deps = Hash.new { |h, k| h[k] = [] }
|
||||||
|
@indirect_deps = []
|
||||||
|
@undeclared_deps = []
|
||||||
|
@unnecessary_deps = []
|
||||||
|
|
||||||
|
check_dylibs
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_normal_output
|
def display_normal_output
|
||||||
display_items "System libraries", system_dylibs
|
display_items "System libraries", @system_dylibs
|
||||||
display_items "Homebrew libraries", brewed_dylibs
|
display_items "Homebrew libraries", @brewed_dylibs
|
||||||
display_items "Indirect dependencies with linkage", indirect_deps
|
display_items "Indirect dependencies with linkage", @indirect_deps
|
||||||
display_items "Variable-referenced libraries", variable_dylibs
|
display_items "Variable-referenced libraries", @variable_dylibs
|
||||||
display_items "Missing libraries", broken_dylibs
|
display_items "Missing libraries", @broken_dylibs
|
||||||
display_items "Broken dependencies", broken_deps
|
display_items "Broken dependencies", @broken_deps
|
||||||
display_items "Undeclared dependencies with linkage", undeclared_deps
|
display_items "Undeclared dependencies with linkage", @undeclared_deps
|
||||||
display_items "Dependencies with no linkage", unnecessary_deps
|
display_items "Dependencies with no linkage", @unnecessary_deps
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_reverse_output
|
def display_reverse_output
|
||||||
return if reverse_links.empty?
|
return if @reverse_links.empty?
|
||||||
sorted = reverse_links.sort
|
@reverse_links.sort.each do |dylib, files|
|
||||||
sorted.each do |dylib, files|
|
|
||||||
puts dylib
|
puts dylib
|
||||||
files.each do |f|
|
files.each do |f|
|
||||||
unprefixed = f.to_s.strip_prefix "#{keg}/"
|
unprefixed = f.to_s.strip_prefix "#{keg}/"
|
||||||
puts " #{unprefixed}"
|
puts " #{unprefixed}"
|
||||||
end
|
end
|
||||||
puts unless dylib == sorted.last[0]
|
puts if dylib != sorted.last.first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_test_output(puts_output: true)
|
def display_test_output(puts_output: true)
|
||||||
display_items "Missing libraries", broken_dylibs, puts_output: puts_output
|
display_items "Missing libraries", @broken_dylibs, puts_output: puts_output
|
||||||
display_items "Broken dependencies", broken_deps, puts_output: puts_output
|
display_items "Broken dependencies", @broken_deps, puts_output: puts_output
|
||||||
puts "No broken library linkage" unless broken_library_linkage?
|
puts "No broken library linkage" unless broken_library_linkage?
|
||||||
end
|
end
|
||||||
|
|
||||||
def broken_library_linkage?
|
def broken_library_linkage?
|
||||||
!broken_dylibs.empty? || !broken_deps.empty?
|
!@broken_dylibs.empty? || !@broken_deps.empty?
|
||||||
end
|
|
||||||
|
|
||||||
def undeclared_deps
|
|
||||||
@undeclared_deps ||= store.fetch_type(:undeclared_deps)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :keg, :formula, :store
|
attr_reader :keg, :formula, :store
|
||||||
|
|
||||||
# 'Hash-type' cache values
|
|
||||||
|
|
||||||
def brewed_dylibs
|
|
||||||
@brewed_dylibs ||= store.fetch_type(:brewed_dylibs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def reverse_links
|
|
||||||
@reverse_links ||= store.fetch_type(:reverse_links)
|
|
||||||
end
|
|
||||||
|
|
||||||
def broken_deps
|
|
||||||
@broken_deps ||= store.fetch_type(:broken_deps)
|
|
||||||
end
|
|
||||||
|
|
||||||
# 'Path-type' cached values
|
|
||||||
|
|
||||||
def system_dylibs
|
|
||||||
@system_dylibs ||= store.fetch_type(:system_dylibs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def broken_dylibs
|
|
||||||
@broken_dylibs ||= store.fetch_type(:broken_dylibs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def variable_dylibs
|
|
||||||
@variable_dylibs ||= store.fetch_type(:variable_dylibs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def indirect_deps
|
|
||||||
@indirect_deps ||= store.fetch_type(:indirect_deps)
|
|
||||||
end
|
|
||||||
|
|
||||||
def unnecessary_deps
|
|
||||||
@unnecessary_deps ||= store.fetch_type(:unnecessary_deps)
|
|
||||||
end
|
|
||||||
|
|
||||||
def dylib_to_dep(dylib)
|
def dylib_to_dep(dylib)
|
||||||
dylib =~ %r{#{Regexp.escape(HOMEBREW_PREFIX)}/(opt|Cellar)/([\w+-.@]+)/}
|
dylib =~ %r{#{Regexp.escape(HOMEBREW_PREFIX)}/(opt|Cellar)/([\w+-.@]+)/}
|
||||||
Regexp.last_match(2)
|
Regexp.last_match(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def flush_cache_and_check_dylibs
|
def check_dylibs
|
||||||
reset_dylibs!
|
keg_files_dylibs_was_empty = false
|
||||||
|
keg_files_dylibs = store&.fetch_type(:keg_files_dylibs)
|
||||||
checked_dylibs = Set.new
|
keg_files_dylibs ||= {}
|
||||||
|
if keg_files_dylibs.empty?
|
||||||
|
keg_files_dylibs_was_empty = true
|
||||||
@keg.find do |file|
|
@keg.find do |file|
|
||||||
next if file.symlink? || file.directory?
|
next if file.symlink? || file.directory?
|
||||||
next if !file.dylib? && !file.binary_executable? && !file.mach_o_bundle?
|
next if !file.dylib? && !file.binary_executable? && !file.mach_o_bundle?
|
||||||
|
|
||||||
# weakly loaded dylibs may not actually exist on disk, so skip them
|
# weakly loaded dylibs may not actually exist on disk, so skip them
|
||||||
# when checking for broken linkage
|
# when checking for broken linkage
|
||||||
|
keg_files_dylibs[file] =
|
||||||
file.dynamically_linked_libraries(except: :LC_LOAD_WEAK_DYLIB)
|
file.dynamically_linked_libraries(except: :LC_LOAD_WEAK_DYLIB)
|
||||||
.each do |dylib|
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
checked_dylibs = Set.new
|
||||||
|
|
||||||
|
keg_files_dylibs.each do |file, dylibs|
|
||||||
|
dylibs.each do |dylib|
|
||||||
@reverse_links[dylib] << file
|
@reverse_links[dylib] << file
|
||||||
|
|
||||||
next if checked_dylibs.include? dylib
|
next if checked_dylibs.include? dylib
|
||||||
|
checked_dylibs << dylib
|
||||||
|
|
||||||
if dylib.start_with? "@"
|
if dylib.start_with? "@"
|
||||||
@variable_dylibs << dylib
|
@variable_dylibs << dylib
|
||||||
else
|
next
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
owner = Keg.for Pathname.new(dylib)
|
owner = Keg.for Pathname.new(dylib)
|
||||||
rescue NotAKegError
|
rescue NotAKegError
|
||||||
@ -136,15 +117,16 @@ class LinkageChecker
|
|||||||
@brewed_dylibs[f] << dylib
|
@brewed_dylibs[f] << dylib
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
checked_dylibs << dylib
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula
|
if formula
|
||||||
@indirect_deps, @undeclared_deps, @unnecessary_deps =
|
@indirect_deps, @undeclared_deps, @unnecessary_deps =
|
||||||
check_undeclared_deps
|
check_undeclared_deps
|
||||||
end
|
end
|
||||||
store_dylibs!
|
|
||||||
|
return unless keg_files_dylibs_was_empty
|
||||||
|
|
||||||
|
store&.update!(keg_files_dylibs: keg_files_dylibs)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_undeclared_deps
|
def check_undeclared_deps
|
||||||
@ -243,33 +225,4 @@ class LinkageChecker
|
|||||||
rescue FormulaUnavailableError
|
rescue FormulaUnavailableError
|
||||||
opoo "Formula unavailable: #{keg.name}"
|
opoo "Formula unavailable: #{keg.name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper function to reset dylib values
|
|
||||||
def reset_dylibs!
|
|
||||||
store&.flush_cache!
|
|
||||||
@system_dylibs = Set.new
|
|
||||||
@broken_dylibs = Set.new
|
|
||||||
@variable_dylibs = Set.new
|
|
||||||
@brewed_dylibs = Hash.new { |h, k| h[k] = Set.new }
|
|
||||||
@reverse_links = Hash.new { |h, k| h[k] = Set.new }
|
|
||||||
@broken_deps = Hash.new { |h, k| h[k] = [] }
|
|
||||||
@indirect_deps = []
|
|
||||||
@undeclared_deps = []
|
|
||||||
@unnecessary_deps = []
|
|
||||||
end
|
|
||||||
|
|
||||||
# Updates data store with package path values
|
|
||||||
def store_dylibs!
|
|
||||||
store&.update!(
|
|
||||||
system_dylibs: system_dylibs,
|
|
||||||
variable_dylibs: variable_dylibs,
|
|
||||||
broken_dylibs: broken_dylibs,
|
|
||||||
indirect_deps: indirect_deps,
|
|
||||||
broken_deps: broken_deps,
|
|
||||||
undeclared_deps: undeclared_deps,
|
|
||||||
unnecessary_deps: unnecessary_deps,
|
|
||||||
brewed_dylibs: brewed_dylibs,
|
|
||||||
reverse_links: reverse_links,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class Tab < OpenStruct
|
|||||||
# Instantiates a Tab for a new installation of a formula.
|
# Instantiates a Tab for a new installation of a formula.
|
||||||
def self.create(formula, compiler, stdlib)
|
def self.create(formula, compiler, stdlib)
|
||||||
build = formula.build
|
build = formula.build
|
||||||
runtime_deps = formula.runtime_dependencies(read_from_tab: false)
|
runtime_deps = formula.declared_runtime_dependencies
|
||||||
attributes = {
|
attributes = {
|
||||||
"homebrew_version" => HOMEBREW_VERSION,
|
"homebrew_version" => HOMEBREW_VERSION,
|
||||||
"used_options" => build.used_options.as_flags,
|
"used_options" => build.used_options.as_flags,
|
||||||
|
|||||||
@ -32,20 +32,13 @@ describe LinkageCacheStore do
|
|||||||
context "a `value` is a `Hash`" do
|
context "a `value` is a `Hash`" do
|
||||||
it "sets the cache for the `keg_name`" do
|
it "sets the cache for the `keg_name`" do
|
||||||
expect(database).to receive(:set).with(keg_name, anything)
|
expect(database).to receive(:set).with(keg_name, anything)
|
||||||
subject.update!(a_value: { key: ["value"] })
|
subject.update!(keg_files_dylibs: { key: ["value"] })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "a `value` is an `Array`" do
|
context "a `value` is not a `Hash`" do
|
||||||
it "sets the cache for the `keg_name`" do
|
it "raises a `TypeError` if a `value` is not a `Hash`" do
|
||||||
expect(database).to receive(:set).with(keg_name, anything)
|
expect { subject.update!(a_value: ["value"]) }.to raise_error(TypeError)
|
||||||
subject.update!(a_value: ["value"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a `value` is not an `Array` or `Hash`" do
|
|
||||||
it "raises a `TypeError` if a `value` is not an `Array` or `Hash`" do
|
|
||||||
expect { subject.update!(key: 1) }.to raise_error(TypeError)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -64,21 +57,11 @@ describe LinkageCacheStore do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "returns a `Hash` of values" do
|
it "returns a `Hash` of values" do
|
||||||
expect(subject.fetch_type(:brewed_dylibs)).to be_an_instance_of(Hash)
|
expect(subject.fetch_type(:keg_files_dylibs)).to be_an_instance_of(Hash)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "`ARRAY_LINKAGE_TYPES.include?(type)`" do
|
context "`type` not in `HASH_LINKAGE_TYPES`" do
|
||||||
before(:each) do
|
|
||||||
expect(database).to receive(:get).with(keg_name).and_return(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns an `Array` of values" do
|
|
||||||
expect(subject.fetch_type(:system_dylibs)).to be_an_instance_of(Array)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "`type` not in `HASH_LINKAGE_TYPES` or `ARRAY_LINKAGE_TYPES`" do
|
|
||||||
it "raises a `TypeError` if the `type` is not supported" do
|
it "raises a `TypeError` if the `type` is not supported" do
|
||||||
expect { subject.fetch_type(:bad_type) }.to raise_error(TypeError)
|
expect { subject.fetch_type(:bad_type) }.to raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user