-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
251 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,31 @@ | ||
|
||
require "test/unit" | ||
|
||
require File.dirname(File.dirname(File.expand_path(__FILE__))) + '/bin/RubyFrontier/longestJourneyUtilities.rb' | ||
|
||
class TestClassof < Test::Unit::TestCase | ||
def test_classof | ||
assert_equal Object, classof(Object) | ||
assert_equal Object, classof(Object.new) | ||
assert_equal TestClassof, classof(self) | ||
assert_equal TestClassof, classof(self.class) | ||
begin | ||
require "minitest/autorun" | ||
rescue LoadError | ||
require 'rubygems' | ||
require 'minitest/autorun' | ||
end | ||
|
||
# classof top-level utility | ||
|
||
class Classof < MiniTest::Spec | ||
# class does two things: it says "here's a test" and brings "it" to life... | ||
# and it is used as a name if there's a failure | ||
# alternatively, can say something like: | ||
# describe :classof do | ||
it "returns the class when handed a class" do | ||
classof(Object).must_be_same_as Object | ||
classof(String).must_be_same_as String | ||
end | ||
it "returns the class when handed an instance" do | ||
classof(Object.new).must_be_same_as Object | ||
classof("howdy").must_be_same_as String | ||
end | ||
end | ||
it "returns the module when handed a module" do | ||
classof(MiniTest).must_be_same_as MiniTest | ||
end | ||
end | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,108 @@ | ||
|
||
require "test/unit" | ||
begin | ||
require "minitest/autorun" | ||
rescue LoadError | ||
require 'rubygems' | ||
require 'minitest/autorun' | ||
end | ||
|
||
require File.dirname(File.dirname(File.expand_path(__FILE__))) + '/bin/RubyFrontier/longestJourneyUtilities.rb' | ||
|
||
class TestHash < Test::Unit::TestCase | ||
def setup | ||
describe Symbol do | ||
it "responds to downcase" do | ||
:howdy.must_equal :Howdy.downcase | ||
:howdy.must_equal :howdy.downcase | ||
:howdy.must_equal :hOWDY.downcase | ||
:howdy.wont_equal :howdyy.downcase | ||
end | ||
end | ||
|
||
describe Hash do | ||
describe "fetch2" do | ||
before do | ||
@h = {"hey" => 1, :ho => 2, "ho" => 3} | ||
@h2 = {"hey" => 1, "ho" => 3, :ho => 2} # different order | ||
@h3 = Hash.new("yowee").merge @h # different empty-key default | ||
end | ||
it "raises unless key is symbol" do | ||
proc {@h.fetch2("hey")}.must_raise RuntimeError | ||
proc {@h2.fetch2("hey")}.must_raise RuntimeError | ||
proc {@h3.fetch2("hey")}.must_raise RuntimeError | ||
end | ||
it "fetches string key if no symbol key exists" do | ||
@h.fetch2(:hey).must_equal 1 | ||
@h2.fetch2(:hey).must_equal 1 | ||
# TODO: this next line fails; fetches string key only if symbol key returns nil | ||
# according my comment, I cannot change this because to do so breaks BindingMaker | ||
# need to figure out why and fix | ||
# @h3.fetch2(:hey).must_equal 1 | ||
end | ||
it "fetches symbol key if symbol key exists" do | ||
@h.fetch2(:ho).must_equal 2 | ||
@h2.fetch2(:ho).must_equal 2 | ||
@h2.fetch2(:ho).must_equal 2 | ||
end | ||
it "returns default if key doesn't exist" do | ||
@h.fetch2(:ha).must_be_nil | ||
@h2.fetch2(:ha).must_be_nil | ||
@h3.fetch2(:ha).must_equal "yowee" | ||
end | ||
end | ||
end | ||
|
||
describe LCHash do | ||
before do | ||
@h = {"hey" => 1, :ho => 2, "ho" => 3} | ||
@h2 = LCHash.new.merge @h | ||
@h2 = {"hey" => 1, "ho" => 3, :ho => 2} # different order | ||
@lch = LCHash.new.merge(@h) | ||
@lch2 = LCHash.new.merge(@h2) | ||
@lch3 = LCHash.new("yowee").merge(@h) | ||
end | ||
def test_symbollc # symbols are downcaseable | ||
assert_equal(:howdy, :Howdy.downcase) | ||
assert_equal(:howdy, :howdy.downcase) | ||
assert_equal(:howdy, :hOWDY.downcase) | ||
it "returns value given exact key normally" do | ||
@lch["hey"].must_equal 1 | ||
@lch2["hey"].must_equal 1 | ||
@lch3["hey"].must_equal 1 | ||
@lch["ho"].must_equal 3 | ||
@lch2["ho"].must_equal 3 | ||
@lch3["ho"].must_equal 3 | ||
@lch[:ho].must_equal 2 | ||
@lch2[:ho].must_equal 2 | ||
@lch3[:ho].must_equal 2 | ||
end | ||
def test_fetch2 | ||
assert_raises RuntimeError do | ||
@h.fetch2("hey") # key must be a symbol | ||
end | ||
assert_equal(1, @h.fetch2(:hey)) # symbol key fetches using string key | ||
assert_equal(2, @h.fetch2(:ho)) # symbol key works normally, prior to string | ||
assert_nil(@h.fetch2(:ha)) # non-existent key returns nil as usual | ||
it "returns value given key incorrectly cased" do | ||
@lch["hEy"].must_equal 1 | ||
@lch2["Hey"].must_equal 1 | ||
@lch3["heY"].must_equal 1 | ||
@lch["hO"].must_equal 3 | ||
@lch2["Ho"].must_equal 3 | ||
@lch3["HO"].must_equal 3 | ||
@lch[:Ho].must_equal 2 | ||
@lch2[:hO].must_equal 2 | ||
@lch3[:HO].must_equal 2 | ||
end | ||
def test_lchash # LCHash: keys work even if you throw uppercase string or symbol at it | ||
assert_equal(1, @h2["Hey"]) | ||
assert_equal(1, @h2["hey"]) | ||
assert_equal(nil, @h["Hey"]) | ||
assert_equal(2, @h2[:Ho]) | ||
assert_equal(2, @h2[:ho]) | ||
assert_equal(nil, @h[:Ho]) | ||
describe "fetch2" do | ||
it "raises unless key is symbol" do | ||
proc {@lch.fetch2("hey")}.must_raise RuntimeError | ||
proc {@lch2.fetch2("hey")}.must_raise RuntimeError | ||
proc {@lch3.fetch2("hey")}.must_raise RuntimeError | ||
end | ||
it "fetches string key if no symbol key exists" do | ||
@lch.fetch2(:Hey).must_equal 1 | ||
@lch2.fetch2(:hEy).must_equal 1 | ||
# TODO: this next line fails; fetches string key only if symbol key returns nil | ||
# according my comment, I cannot change this because to do so breaks BindingMaker | ||
# need to figure out why and fix | ||
# @h3.fetch2(:heY).must_equal 1 | ||
end | ||
it "fetches symbol key if symbol key exists" do | ||
@lch.fetch2(:Ho).must_equal 2 | ||
@lch2.fetch2(:hO).must_equal 2 | ||
@lch2.fetch2(:HO).must_equal 2 | ||
end | ||
it "returns default if key doesn't exist" do | ||
@lch.fetch2(:Ha).must_be_nil | ||
@lch2.fetch2(:hA).must_be_nil | ||
@lch3.fetch2(:HA).must_equal "yowee" | ||
end | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,137 @@ | ||
require "test/unit" | ||
#require "test/unit" | ||
|
||
require File.dirname(File.dirname(File.expand_path(__FILE__))) + '/bin/RubyFrontier/longestJourneyUtilities.rb' | ||
|
||
class Memoizer | ||
def initialize | ||
@memoize = true | ||
begin | ||
require "minitest/autorun" | ||
rescue LoadError | ||
require 'rubygems' | ||
require 'minitest/autorun' | ||
end | ||
|
||
#class Memoize < MiniTest::Spec | ||
describe "memoization of a class method" do | ||
before do | ||
# let's memoize a class method | ||
class Memoizer | ||
class << self | ||
def randy2(s) | ||
rand | ||
end | ||
extend Memoizable | ||
memoize :randy2 | ||
end | ||
end | ||
# let's obtain a memoized result | ||
@origarg = "howdy" | ||
@randy2memoized = Memoizer.randy2(@origarg) | ||
end | ||
def randy(s) | ||
rand | ||
# just for safety, we can destroy our test Memoizer class... | ||
# ...so it doesn't wash over into the next test | ||
after do | ||
Object.send :remove_const, :Memoizer | ||
end | ||
def domem(tf) | ||
@memoize = tf | ||
|
||
it "gives memoized result if args are the same" do | ||
Memoizer.randy2(@origarg).must_equal @randy2memoized | ||
end | ||
def showcache | ||
@@memoized_randy | ||
it "gives a different result if args are not the same" do | ||
Memoizer.randy2(@origarg + "not").wont_equal @randy2memoized | ||
end | ||
extend Memoizable | ||
memoize :randy | ||
end | ||
|
||
class Memoizer | ||
class << self | ||
def randy2(s) | ||
rand | ||
describe "memoization of a class method in a module" do | ||
before do | ||
# let's memoize a module method | ||
module Memoizer | ||
class << self | ||
def randy3(s) | ||
rand | ||
end | ||
extend Memoizable | ||
memoize :randy3 | ||
end | ||
end | ||
extend Memoizable | ||
memoize :randy2 | ||
# let's obtain a memoized result | ||
@origarg = "howdy" | ||
@randy3memoized = Memoizer.randy3(@origarg) | ||
end | ||
# just for safety, we can destroy our test Memoizer class... | ||
# ...so it doesn't wash over into the next test | ||
after do | ||
Object.send :remove_const, :Memoizer | ||
end | ||
|
||
it "gives memoized result if args are the same" do | ||
Memoizer.randy3(@origarg).must_equal @randy3memoized | ||
end | ||
it "gives a different result if args are not the same" do | ||
Memoizer.randy3(@origarg + "not").wont_equal @randy3memoized | ||
end | ||
end | ||
|
||
class TestMemoize < Test::Unit::TestCase | ||
def test_memoize | ||
mem = Memoizer.new | ||
res = mem.randy("howdy") | ||
# if args are the same, result is the same | ||
assert_equal res, mem.randy("howdy") | ||
# if args are not the same, result is not the same | ||
assert_not_equal res, mem.randy("howdy2") | ||
# backdoor on-off switch | ||
mem.domem false | ||
assert_not_equal res, mem.randy("howdy") | ||
mem.domem true | ||
assert_equal res, mem.randy("howdy") | ||
# access original method | ||
assert_raises(NoMethodError) do # private | ||
mem.__unmemoized_randy__ "howdy" | ||
describe "memoization of an instance method" do | ||
before do | ||
# let's memoize an instance method | ||
class Memoizer | ||
def randy(s) | ||
rand | ||
end | ||
extend Memoizable | ||
memoize :randy | ||
end | ||
# let's make an instance and obtain a memoized result | ||
@mem = Memoizer.new | ||
@origarg = "howdy" | ||
@randymemoized = @mem.randy(@origarg) | ||
# here's how to peek at the cache (class_variable_get is private in Ruby 1.8) | ||
@the_cache = @mem.class.send :class_variable_get, :@@memoized_randy | ||
end | ||
# just for safety, we can destroy our test Memoizer class... | ||
# ...so it doesn't wash over into the next test | ||
after do | ||
Object.send :remove_const, :Memoizer | ||
end | ||
|
||
it "gives memoized result if args are the same" do | ||
@mem.randy(@origarg).must_equal @randymemoized | ||
@mem.randy(@origarg).must_equal @mem.randy(@origarg) | ||
end | ||
it "gives a different result if args are not the same" do | ||
@mem.randy(@origarg + "not").wont_equal @randymemoized | ||
end | ||
it "gives a different result if args are the same but backdoor switch is turned off" do | ||
@mem.instance_variable_set :@memoize, false | ||
@mem.randy(@origarg).wont_equal @randymemoized | ||
@mem.randy(@origarg).wont_equal @mem.randy(@origarg) | ||
# setting to nil is like setting to true, it turns the backdoor switch back on | ||
@mem.instance_variable_set :@memoize, nil | ||
@mem.randy(@origarg).must_equal @randymemoized | ||
@mem.randy(@origarg).must_equal @mem.randy(@origarg) | ||
@mem.instance_variable_set :@memoize, true | ||
@mem.randy(@origarg).must_equal @randymemoized | ||
@mem.randy(@origarg).must_equal @mem.randy(@origarg) | ||
end | ||
|
||
it "has privatized the original method" do | ||
privateMethodCall = proc {@mem.__unmemoized_randy__ @origarg} | ||
privateMethodCall.must_raise NoMethodError | ||
privateMethodCall.call rescue $!.message.must_match(/private/) | ||
# but of course we can bypass that privacy using send | ||
privateMethodSend = proc {@mem.send :__unmemoized_randy__, @origarg} | ||
privateMethodSend.call.wont_equal privateMethodSend.call | ||
end | ||
|
||
it "caches in a hash" do | ||
@the_cache.must_be_instance_of Hash | ||
end | ||
describe "details of the hash" do | ||
it "keys on array of args" do | ||
@the_cache.fetch(Array(@origarg)).wont_be_nil | ||
end | ||
it "marshals the value" do | ||
Marshal.load(@the_cache[Array(@origarg)]).must_equal @mem.randy(@origarg) | ||
end | ||
assert_not_equal res, mem.send(:__unmemoized_randy__, "howdy") # bypass privacy | ||
# direct inspection of cache | ||
cache = mem.showcache | ||
assert_kind_of(Hash, cache) | ||
assert_equal(2, cache.length) # once for howdy, once for howdy2 | ||
# direct access to contents of cache | ||
# notice that our original args have been arrayified to form key | ||
# contents are marshalled to prevent accidental direct mutation within cache | ||
assert_equal res, Marshal.load(cache[Array("howdy")]) | ||
# also works for class methods | ||
res = Memoizer.randy2("howdy") | ||
# if args are the same, result is the same | ||
assert_equal res, Memoizer.randy2("howdy") | ||
# if args are not the same, result is not the same | ||
assert_not_equal res, Memoizer.randy2("howdy2") | ||
end | ||
end | ||
|