summaryrefslogtreecommitdiffstats
path: root/spec/unit/util
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-05-15 14:30:29 -0500
committerLuke Kanies <luke@madstop.com>2008-05-15 14:30:29 -0500
commit1ba2bed578debd251d2b9514039082eaa3f136df (patch)
tree907098a846dd7215d59ccfec2d470318bb619fa8 /spec/unit/util
parentbe0a8031fbf8e4a2d608ab600c37c1b01dec16a1 (diff)
downloadfacter-1ba2bed578debd251d2b9514039082eaa3f136df.tar.gz
facter-1ba2bed578debd251d2b9514039082eaa3f136df.tar.xz
facter-1ba2bed578debd251d2b9514039082eaa3f136df.zip
Moving all of the support classes to util/.
This makes it easier for our loader to distinguish between code that Facter uses and new facts.
Diffstat (limited to 'spec/unit/util')
-rwxr-xr-xspec/unit/util/collection.rb177
-rwxr-xr-xspec/unit/util/confine.rb75
-rwxr-xr-xspec/unit/util/fact.rb129
-rwxr-xr-xspec/unit/util/loader.rb190
-rwxr-xr-xspec/unit/util/resolution.rb168
5 files changed, 739 insertions, 0 deletions
diff --git a/spec/unit/util/collection.rb b/spec/unit/util/collection.rb
new file mode 100755
index 0000000..e88de06
--- /dev/null
+++ b/spec/unit/util/collection.rb
@@ -0,0 +1,177 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'facter/util/collection'
+
+describe Facter::Util::Collection do
+ it "should have a method for adding facts" do
+ Facter::Util::Collection.new.should respond_to(:add)
+ end
+
+ describe "when adding facts" do
+ before do
+ @coll = Facter::Util::Collection.new
+ end
+
+ it "should create a new fact if no fact with the same name already exists" do
+ fact = mock 'fact'
+ Facter::Util::Fact.expects(:new).with { |name, *args| name == :myname }.returns fact
+
+ @coll.add(:myname)
+ end
+
+ describe "and a block is provided" do
+ it "should use the block to add a resolution to the fact" do
+ fact = mock 'fact'
+ Facter::Util::Fact.expects(:new).returns fact
+
+ fact.expects(:add)
+
+ @coll.add(:myname) {}
+ end
+ end
+ end
+
+ it "should have a method for retrieving facts by name" do
+ Facter::Util::Collection.new.should respond_to(:fact)
+ end
+
+ describe "when retrieving facts" do
+ before do
+ @coll = Facter::Util::Collection.new
+
+ @fact = @coll.add("YayNess")
+ end
+
+ it "should return the fact instance specified by the name" do
+ @coll.fact("YayNess").should equal(@fact)
+ end
+
+ it "should be case-insensitive" do
+ @coll.fact("yayness").should equal(@fact)
+ end
+
+ it "should treat strings and symbols equivalently" do
+ @coll.fact(:yayness).should equal(@fact)
+ end
+ end
+
+ it "should have a method for returning a fact's value" do
+ Facter::Util::Collection.new.should respond_to(:value)
+ end
+
+ describe "when returning a fact's value" do
+ before do
+ @coll = Facter::Util::Collection.new
+ @fact = @coll.add("YayNess")
+
+ @fact.stubs(:value).returns "result"
+ end
+
+ it "should return the result of calling :value on the fact" do
+ @fact.expects(:value).returns "result"
+
+ @coll.value("YayNess").should == "result"
+ end
+
+ it "should be case-insensitive" do
+ @coll.value("yayness").should_not be_nil
+ end
+
+ it "should treat strings and symbols equivalently" do
+ @coll.value(:yayness).should_not be_nil
+ end
+ end
+
+ it "should return the fact's value when the array index method is used" do
+ @coll = Facter::Util::Collection.new
+ @coll.expects(:value).with("myfact").returns "foo"
+ @coll["myfact"].should == "foo"
+ end
+
+ it "should have a method for flushing all facts" do
+ @coll = Facter::Util::Collection.new
+ @fact = @coll.add("YayNess")
+
+ @fact.expects(:flush)
+
+ @coll.flush
+ end
+
+ it "should have a method that returns all fact names" do
+ @coll = Facter::Util::Collection.new
+ @coll.add(:one)
+ @coll.add(:two)
+
+ @coll.list.sort.should == [:one, :two].sort
+ end
+
+ it "should have a method for returning a hash of fact values" do
+ Facter::Util::Collection.new.should respond_to(:to_hash)
+ end
+
+ describe "when returning a hash of values" do
+ before do
+ @coll = Facter::Util::Collection.new
+ @fact = @coll.add(:one)
+ @fact.stubs(:value).returns "me"
+ end
+
+ it "should return a hash of fact names and values with the fact names as strings" do
+ @coll.to_hash.should == {"one" => "me"}
+ end
+
+ it "should not include facts that did not return a value" do
+ f = @coll.add(:two)
+ f.stubs(:value).returns nil
+ @coll.to_hash.should_not be_include(:two)
+ end
+ end
+
+ it "should have a method for iterating over all facts" do
+ Facter::Util::Collection.new.should respond_to(:each)
+ end
+
+ it "should include Enumerable" do
+ Facter::Util::Collection.ancestors.should be_include(Enumerable)
+ end
+
+ describe "when iterating over facts" do
+ before do
+ @coll = Facter::Util::Collection.new
+ @one = @coll.add(:one)
+ @two = @coll.add(:two)
+ end
+
+ it "should yield each fact name and the fact value" do
+ @one.stubs(:value).returns "ONE"
+ @two.stubs(:value).returns "TWO"
+ facts = {}
+ @coll.each do |fact, value|
+ facts[fact] = value
+ end
+ facts.should == {"one" => "ONE", "two" => "TWO"}
+ end
+
+ it "should convert the fact name to a string" do
+ @one.stubs(:value).returns "ONE"
+ @two.stubs(:value).returns "TWO"
+ facts = {}
+ @coll.each do |fact, value|
+ fact.should be_instance_of(String)
+ end
+ end
+
+ it "should only yield facts that have values" do
+ @one.stubs(:value).returns "ONE"
+ @two.stubs(:value).returns nil
+ facts = {}
+ @coll.each do |fact, value|
+ facts[fact] = value
+ end
+
+ facts.should_not be_include("two")
+ end
+ end
+end
diff --git a/spec/unit/util/confine.rb b/spec/unit/util/confine.rb
new file mode 100755
index 0000000..5c1ce3b
--- /dev/null
+++ b/spec/unit/util/confine.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'facter/util/confine'
+
+describe Facter::Util::Confine do
+ it "should require a fact name" do
+ Facter::Util::Confine.new("yay", true).fact.should == "yay"
+ end
+
+ it "should accept a value specified individually" do
+ Facter::Util::Confine.new("yay", "test").values.should == ["test"]
+ end
+
+ it "should accept multiple values specified at once" do
+ Facter::Util::Confine.new("yay", "test", "other").values.should == ["test", "other"]
+ end
+
+ it "should convert all values to strings" do
+ Facter::Util::Confine.new("yay", :test).values.should == %w{test}
+ end
+
+ it "should fail if no fact name is provided" do
+ lambda { Facter::Util::Confine.new(nil, :test) }.should raise_error(ArgumentError)
+ end
+
+ it "should fail if no values were provided" do
+ lambda { Facter::Util::Confine.new("yay") }.should raise_error(ArgumentError)
+ end
+
+ it "should have a method for testing whether it matches" do
+ Facter::Util::Confine.new("yay", :test).should respond_to(:true?)
+ end
+
+ describe "when evaluating" do
+ before do
+ @confine = Facter::Util::Confine.new("yay", "one", "two")
+ @fact = mock 'fact'
+ Facter.stubs(:[]).returns @fact
+ end
+
+ it "should return false if the fact does not exist" do
+ Facter.expects(:[]).with("yay").returns nil
+
+ @confine.true?.should be_false
+ end
+
+ it "should use the returned fact to get the value" do
+ Facter.expects(:[]).with("yay").returns @fact
+
+ @fact.expects(:value).returns nil
+
+ @confine.true?
+ end
+
+ it "should return false if the fact has no value" do
+ @fact.stubs(:value).returns nil
+
+ @confine.true?.should be_false
+ end
+
+ it "should return true if any of the provided values matches the fact's value" do
+ @fact.stubs(:value).returns "two"
+
+ @confine.true?.should be_true
+ end
+
+ it "should return false if none of the provided values matches the fact's value" do
+ @fact.stubs(:value).returns "three"
+
+ @confine.true?.should be_false
+ end
+ end
+end
diff --git a/spec/unit/util/fact.rb b/spec/unit/util/fact.rb
new file mode 100755
index 0000000..1652032
--- /dev/null
+++ b/spec/unit/util/fact.rb
@@ -0,0 +1,129 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'facter/util/fact'
+
+describe Facter::Util::Fact do
+ it "should require a name" do
+ lambda { Facter::Util::Fact.new }.should raise_error(ArgumentError)
+ end
+
+ it "should always downcase the name and convert it to a symbol" do
+ Facter::Util::Fact.new("YayNess").name.should == :yayness
+ end
+
+ it "should default to its name converted to a string as its ldapname" do
+ Facter::Util::Fact.new("YayNess").ldapname.should == "yayness"
+ end
+
+ it "should allow specifying the ldap name at initialization" do
+ Facter::Util::Fact.new("YayNess", :ldapname => "fooness").ldapname.should == "fooness"
+ end
+
+ it "should fail if an unknown option is provided" do
+ lambda { Facter::Util::Fact.new('yay', :foo => :bar) }.should raise_error(ArgumentError)
+ end
+
+ it "should have a method for adding resolution mechanisms" do
+ Facter::Util::Fact.new("yay").should respond_to(:add)
+ end
+
+ describe "when adding resolution mechanisms" do
+ before do
+ @fact = Facter::Util::Fact.new("yay")
+
+ @resolution = mock 'resolution'
+ @resolution.stub_everything
+
+ end
+
+ it "should fail if no block is given" do
+ lambda { @fact.add }.should raise_error(ArgumentError)
+ end
+
+ it "should create a new resolution instance" do
+ Facter::Util::Resolution.expects(:new).returns @resolution
+
+ @fact.add { }
+ end
+
+ it "should instance_eval the passed block on the new resolution" do
+ @resolution.expects(:instance_eval)
+
+ Facter::Util::Resolution.stubs(:new).returns @resolution
+
+ @fact.add { }
+ end
+
+ it "should re-sort the resolutions by length, so the most restricted resolutions are first" do
+ r1 = stub 'r1', :length => 1
+ r2 = stub 'r2', :length => 2
+ r3 = stub 'r3', :length => 0
+ Facter::Util::Resolution.expects(:new).times(3).returns(r1).returns(r2).returns(r3)
+ @fact.add { }
+ @fact.add { }
+ @fact.add { }
+
+ @fact.instance_variable_get("@resolves").should == [r2, r1, r3]
+ end
+ end
+
+ it "should be able to return a value" do
+ Facter::Util::Fact.new("yay").should respond_to(:value)
+ end
+
+ describe "when returning a value" do
+ before do
+ @fact = Facter::Util::Fact.new("yay")
+ end
+
+ it "should return nil if there are no resolutions" do
+ Facter::Util::Fact.new("yay").value.should be_nil
+ end
+
+ it "should return the first value returned by a resolution" do
+ r1 = stub 'r1', :length => 2, :value => nil, :suitable? => true
+ r2 = stub 'r2', :length => 1, :value => "yay", :suitable? => true
+ r3 = stub 'r3', :length => 0, :value => "foo", :suitable? => true
+ Facter::Util::Resolution.expects(:new).times(3).returns(r1).returns(r2).returns(r3)
+ @fact.add { }
+ @fact.add { }
+ @fact.add { }
+
+ @fact.value.should == "yay"
+ end
+
+ it "should short-cut returning the value once one is found" do
+ r1 = stub 'r1', :length => 2, :value => "foo", :suitable? => true
+ r2 = stub 'r2', :length => 1, :suitable? => true # would fail if 'value' were asked for
+ Facter::Util::Resolution.expects(:new).times(2).returns(r1).returns(r2)
+ @fact.add { }
+ @fact.add { }
+
+ @fact.value
+ end
+
+ it "should skip unsuitable resolutions" do
+ r1 = stub 'r1', :length => 2, :suitable? => false # would fail if 'value' were asked for'
+ r2 = stub 'r2', :length => 1, :value => "yay", :suitable? => true
+ Facter::Util::Resolution.expects(:new).times(2).returns(r1).returns(r2)
+ @fact.add { }
+ @fact.add { }
+
+ @fact.value.should == "yay"
+ end
+
+ it "should return nil if the value is the empty string" do
+ r1 = stub 'r1', :suitable? => true, :value => ""
+ Facter::Util::Resolution.expects(:new).returns r1
+ @fact.add { }
+
+ @fact.value.should be_nil
+ end
+ end
+
+ it "should have a method for flushing the cached fact" do
+ Facter::Util::Fact.new(:foo).should respond_to(:flush)
+ end
+end
diff --git a/spec/unit/util/loader.rb b/spec/unit/util/loader.rb
new file mode 100755
index 0000000..4c0d777
--- /dev/null
+++ b/spec/unit/util/loader.rb
@@ -0,0 +1,190 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'facter/util/loader'
+
+# Make sure we have a Puppet constant, so we can test
+# loading Puppet facts.
+unless defined?(Puppet)
+ class Puppet; end
+end
+
+describe Facter::Util::Loader do
+ def with_env(values)
+ old = {}
+ values.each do |var, value|
+ if old_val = ENV[var]
+ old[var] = old_val
+ end
+ ENV[var] = value
+ end
+ yield
+ values.each do |var, value|
+ if old.include?(var)
+ ENV[var] = old[var]
+ else
+ ENV.delete(var)
+ end
+ end
+ end
+
+ it "should have a method for loading individual facts by name" do
+ Facter::Util::Loader.new.should respond_to(:load)
+ end
+
+ it "should have a method for loading all facts" do
+ Facter::Util::Loader.new.should respond_to(:load_all)
+ end
+
+ it "should have a method for returning directories containing facts" do
+ Facter::Util::Loader.new.should respond_to(:search_path)
+ end
+
+ describe "when determining the search path" do
+ before do
+ @loader = Facter::Util::Loader.new
+ @settings = mock 'settings'
+ @settings.stubs(:value).returns "/eh"
+ Puppet.stubs(:settings).returns @settings
+ end
+
+ it "should include the facter subdirectory of all paths in ruby LOAD_PATH" do
+ dirs = $LOAD_PATH.collect { |d| File.join(d, "facter") }
+ paths = @loader.search_path
+
+ dirs.each do |dir|
+ paths.should be_include(dir)
+ end
+ end
+
+ describe "and the FACTERLIB environment variable is set" do
+ it "should include all paths in FACTERLIB" do
+ with_env "FACTERLIB" => "/one/path:/two/path" do
+ paths = @loader.search_path
+ %w{/one/path /two/path}.each do |dir|
+ paths.should be_include(dir)
+ end
+ end
+ end
+ end
+
+ describe "and the Puppet libraries are loaded" do
+ it "should include the factdest setting" do
+ @settings.expects(:value).with(:factdest).returns "/my/facts"
+ @loader.search_path.should be_include("/my/facts")
+ end
+
+ it "should include the facter subdirectory of the libdir setting" do
+ @settings.expects(:value).with(:libdir).returns "/lib/dir"
+ @loader.search_path.should be_include("/lib/dir/facter")
+ end
+ end
+ end
+
+ describe "when loading facts" do
+ before do
+ @loader = Facter::Util::Loader.new
+ @loader.stubs(:search_path).returns []
+ end
+
+ it "should load values from the matching environment variable if one is present" do
+ Facter.expects(:add).with("testing")
+
+ with_env "facter_testing" => "yayness" do
+ @loader.load(:testing)
+ end
+ end
+
+ it "should load any files in the search path with names matching the fact name" do
+ @loader.expects(:search_path).returns %w{/one/dir /two/dir}
+ FileTest.stubs(:exist?).returns false
+ FileTest.expects(:exist?).with("/one/dir/testing.rb").returns true
+ FileTest.expects(:exist?).with("/two/dir/testing.rb").returns true
+
+ Kernel.expects(:load).with("/one/dir/testing.rb")
+ Kernel.expects(:load).with("/two/dir/testing.rb")
+
+ @loader.load(:testing)
+ end
+
+ it "should load any ruby files in directories matching the fact name in the search path" do
+ @loader.expects(:search_path).returns %w{/one/dir}
+ FileTest.stubs(:exist?).returns false
+ FileTest.expects(:directory?).with("/one/dir/testing").returns true
+
+ Dir.expects(:entries).with("/one/dir/testing").returns %w{two.rb}
+
+ Kernel.expects(:load).with("/one/dir/testing/two.rb")
+
+ @loader.load(:testing)
+ end
+
+ it "should not load files that don't end in '.rb'" do
+ @loader.expects(:search_path).returns %w{/one/dir}
+ FileTest.stubs(:exist?).returns false
+ FileTest.expects(:directory?).with("/one/dir/testing").returns true
+
+ Dir.expects(:entries).with("/one/dir/testing").returns %w{one}
+
+ Kernel.expects(:load).never
+
+ @loader.load(:testing)
+ end
+ end
+
+ describe "when loading all facts" do
+ before do
+ @loader = Facter::Util::Loader.new
+ @loader.stubs(:search_path).returns []
+ end
+
+ it "should load all files in all search paths" do
+ @loader.expects(:search_path).returns %w{/one/dir /two/dir}
+
+ Dir.expects(:entries).with("/one/dir").returns %w{a.rb b.rb}
+ Dir.expects(:entries).with("/two/dir").returns %w{c.rb d.rb}
+
+ %w{/one/dir/a.rb /one/dir/b.rb /two/dir/c.rb /two/dir/d.rb}.each { |f| Kernel.expects(:load).with(f) }
+
+ @loader.load_all
+ end
+
+ it "should load all files in all subdirectories in all search paths" do
+ @loader.expects(:search_path).returns %w{/one/dir /two/dir}
+
+ Dir.expects(:entries).with("/one/dir").returns %w{a}
+ Dir.expects(:entries).with("/two/dir").returns %w{b}
+
+ %w{/one/dir/a /two/dir/b}.each { |f| File.expects(:directory?).with(f).returns true }
+
+ Dir.expects(:entries).with("/one/dir/a").returns %w{c.rb}
+ Dir.expects(:entries).with("/two/dir/b").returns %w{d.rb}
+
+ %w{/one/dir/a/c.rb /two/dir/b/d.rb}.each { |f| Kernel.expects(:load).with(f) }
+
+ @loader.load_all
+ end
+
+ it "should not load files in the util subdirectory" do
+ @loader.expects(:search_path).returns %w{/one/dir}
+
+ Dir.expects(:entries).with("/one/dir").returns %w{util}
+
+ File.expects(:directory?).with("/one/dir/util").returns true
+
+ Dir.expects(:entries).with("/one/dir/util").never
+
+ @loader.load_all
+ end
+
+ it "should load all facts from the environment" do
+ Facter.expects(:add).with('one')
+ Facter.expects(:add).with('two')
+
+ with_env "facter_one" => "yayness", "facter_two" => "boo" do
+ @loader.load_all
+ end
+ end
+ end
+end
diff --git a/spec/unit/util/resolution.rb b/spec/unit/util/resolution.rb
new file mode 100755
index 0000000..493ee3a
--- /dev/null
+++ b/spec/unit/util/resolution.rb
@@ -0,0 +1,168 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'facter/util/resolution'
+
+describe Facter::Util::Resolution do
+ it "should require a name" do
+ lambda { Facter::Util::Resolution.new }.should raise_error(ArgumentError)
+ end
+
+ it "should have a name" do
+ Facter::Util::Resolution.new("yay").name.should == "yay"
+ end
+
+ it "should have a method for setting the code" do
+ Facter::Util::Resolution.new("yay").should respond_to(:setcode)
+ end
+
+ describe "when setting the code" do
+ before do
+ @resolve = Facter::Util::Resolution.new("yay")
+ end
+
+ it "should default to /bin/sh as the interpreter if a string is provided" do
+ @resolve.setcode "foo"
+ @resolve.interpreter.should == "/bin/sh"
+ end
+
+ it "should set the code to any provided string" do
+ @resolve.setcode "foo"
+ @resolve.code.should == "foo"
+ end
+
+ it "should set the code to any provided block" do
+ block = lambda { }
+ @resolve.setcode(&block)
+ @resolve.code.should equal(block)
+ end
+
+ it "should prefer the string over a block" do
+ @resolve.setcode("foo") { }
+ @resolve.code.should == "foo"
+ end
+
+ it "should fail if neither a string nor block has been provided" do
+ lambda { @resolve.setcode }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "should be able to return a value" do
+ Facter::Util::Resolution.new("yay").should respond_to(:value)
+ end
+
+ describe "when returning the value" do
+ before do
+ @resolve = Facter::Util::Resolution.new("yay")
+ end
+
+ describe "and the code is a string" do
+ it "should return the result of executing the code with the interpreter" do
+ @resolve.setcode "/bin/foo"
+ Facter::Util::Resolution.expects(:exec).with("/bin/foo", "/bin/sh").returns "yup"
+
+ @resolve.value.should == "yup"
+ end
+
+ it "should return nil if the value is an empty string" do
+ @resolve.setcode "/bin/foo"
+ Facter::Util::Resolution.stubs(:exec).returns ""
+ @resolve.value.should be_nil
+ end
+ end
+
+ describe "and the code is a block" do
+ it "should return the value returned by the block" do
+ @resolve.setcode { "yayness" }
+ @resolve.value.should == "yayness"
+ end
+
+ it "should return nil if the value is an empty string" do
+ @resolve.setcode { "" }
+ @resolve.value.should be_nil
+ end
+ end
+ end
+
+ it "should return its value when converted to a string" do
+ @resolve = Facter::Util::Resolution.new("yay")
+ @resolve.expects(:value).returns "myval"
+ @resolve.to_s.should == "myval"
+ end
+
+ it "should allow the adding of confines" do
+ Facter::Util::Resolution.new("yay").should respond_to(:confine)
+ end
+
+ it "should provide a method for returning the number of confines" do
+ @resolve = Facter::Util::Resolution.new("yay")
+ @resolve.confine "one" => "foo", "two" => "fee"
+ @resolve.length.should == 2
+ end
+
+ it "should return 0 confines when no confines have been added" do
+ Facter::Util::Resolution.new("yay").length.should == 0
+ end
+
+ it "should have a method for determining if it is suitable" do
+ Facter::Util::Resolution.new("yay").should respond_to(:suitable?)
+ end
+
+ describe "when adding confines" do
+ before do
+ @resolve = Facter::Util::Resolution.new("yay")
+ end
+
+ it "should accept a hash of fact names and values" do
+ lambda { @resolve.confine :one => "two" }.should_not raise_error
+ end
+
+ it "should create a Util::Confine instance for every argument in the provided hash" do
+ Facter::Util::Confine.expects(:new).with("one", "foo")
+ Facter::Util::Confine.expects(:new).with("two", "fee")
+
+ @resolve.confine "one" => "foo", "two" => "fee"
+ end
+
+ end
+
+ describe "when determining suitability" do
+ before do
+ @resolve = Facter::Util::Resolution.new("yay")
+ end
+
+ it "should always be suitable if no confines have been added" do
+ @resolve.should be_suitable
+ end
+
+ it "should be unsuitable if any provided confines return false" do
+ confine1 = mock 'confine1', :true? => true
+ confine2 = mock 'confine2', :true? => false
+ Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
+ @resolve.confine :one => :two, :three => :four
+
+ @resolve.should_not be_suitable
+ end
+
+ it "should be suitable if all provided confines return true" do
+ confine1 = mock 'confine1', :true? => true
+ confine2 = mock 'confine2', :true? => true
+ Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
+ @resolve.confine :one => :two, :three => :four
+
+ @resolve.should be_suitable
+ end
+ end
+
+ it "should have a class method for executing code" do
+ Facter::Util::Resolution.should respond_to(:exec)
+ end
+
+ # It's not possible, AFAICT, to mock %x{}, so I can't really test this bit.
+ describe "when executing code" do
+ it "should fail if any interpreter other than /bin/sh is requested" do
+ lambda { Facter::Util::Resolution.exec("/something", "/bin/perl") }.should raise_error(ArgumentError)
+ end
+ end
+end