migrate some Cache tests to integration tests

This commit is contained in:
Josh Holtrop 2017-05-22 15:55:18 -04:00
parent bfbbc19728
commit 06cb4b7a55
9 changed files with 213 additions and 190 deletions

View File

@ -1,3 +1,3 @@
Rscons::Environment.new do |env|
env.Program('simple', Dir['*.c'])
env.Program('simple.exe', Dir['*.c'])
end

View File

@ -0,0 +1,4 @@
Rscons::Environment.new do |env|
env["LIBS"] += ["c"]
env.Program('simple.exe', Dir['*.c'])
end

View File

@ -0,0 +1,3 @@
Rscons::Environment.new do |env|
env.Copy("simple.copy", "simple.c")
end

View File

@ -0,0 +1,6 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env.process
env["LDCMD"] = %w[gcc -o ${_TARGET} simple.o]
env.Program('simple.exe', [])
end

View File

@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env.Object("simple.o", "simple.c")
env["LDCMD"] = %w[gcc -o ${_TARGET} simple.o]
env.Program('simple.exe', ["simple.o"])
end

View File

@ -0,0 +1,5 @@
Rscons::Environment.new do |env|
env.Program("simple.exe", "simple.c")
user_deps = File.read("user_deps", mode: "rb").split(" ")
env.depends("simple.exe", *user_deps)
end

View File

@ -0,0 +1,19 @@
class StrictBuilder < Rscons::Builder
def run(options)
target, sources, cache, env = options.values_at(:target, :sources, :cache, :env)
command = %W[gcc -o #{target}] + sources.sort
unless cache.up_to_date?(target, command, sources, env, strict_deps: true)
return false unless env.execute("StrictBuilder #{target}", command)
cache.register_build(target, command, sources, env)
end
target
end
end
Rscons::Environment.new(echo: :command) do |env|
env.add_builder(StrictBuilder.new)
env.Object("one.o", "one.c", "CCFLAGS" => %w[-DONE])
env.Object("two.o", "two.c")
sources = File.read("sources", mode: "rb").split(" ")
env.StrictBuilder("program.exe", sources)
end

View File

@ -106,7 +106,7 @@ EOF
result = run_test
expect(result.stderr).to eq ""
expect(File.exists?('simple.o')).to be_truthy
expect(`./simple`).to eq "This is a simple C program\n"
expect(`./simple.exe`).to eq "This is a simple C program\n"
end
it 'prints commands as they are executed' do
@ -766,4 +766,173 @@ EOF
end
end
context "Cache management" do
it "prints a warning when the cache is corrupt" do
test_dir("simple")
File.open(Rscons::Cache::CACHE_FILE, "w") do |fh|
fh.puts("[1]")
end
result = run_test
expect(result.stderr).to match /Warning.*was corrupt. Contents:/
end
it "removes the cache file on a clean operation" do
test_dir("simple")
result = run_test
expect(result.stderr).to eq ""
expect(File.exists?(Rscons::Cache::CACHE_FILE)).to be_truthy
result = run_test(rscons_args: %w[-c])
expect(result.stderr).to eq ""
expect(File.exists?(Rscons::Cache::CACHE_FILE)).to be_falsey
end
it "forces a build when the target file does not exist and is not in the cache" do
test_dir("simple")
expect(File.exists?("simple.exe")).to be_falsey
result = run_test
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
end
it "forces a build when the target file does exist but is not in the cache" do
test_dir("simple")
File.open("simple.exe", "wb") do |fh|
fh.write("hi")
end
result = run_test
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
expect(File.read("simple.exe", mode: "rb")).to_not eq "hi"
end
it "forces a build when the target file exists and is in the cache but has changed since cached" do
test_dir("simple")
result = run_test
expect(result.stderr).to eq ""
File.open("simple.exe", "wb") do |fh|
fh.write("hi")
end
test_dir("simple")
result = run_test
expect(result.stderr).to eq ""
expect(File.exists?("simple.exe")).to be_truthy
expect(File.read("simple.exe", mode: "rb")).to_not eq "hi"
end
it "forces a build when the command changes" do
test_dir("simple")
result = run_test
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"CC simple.o",
"LD simple.exe",
]
result = run_test(rsconsfile: "cache_command_change.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"LD simple.exe",
]
end
it "forces a build when there is a new dependency" do
test_dir("simple")
result = run_test(rsconsfile: "cache_new_dep1.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"CC simple.o",
"LD simple.exe",
]
result = run_test(rsconsfile: "cache_new_dep2.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"LD simple.exe",
]
end
it "forces a build when a dependency's checksum has changed" do
test_dir("simple")
result = run_test(rsconsfile: "cache_dep_checksum_change.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq ["Copy simple.copy"]
File.open("simple.c", "wb") do |fh|
fh.write("hi")
end
result = run_test(rsconsfile: "cache_dep_checksum_change.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq ["Copy simple.copy"]
end
it "forces a rebuild with strict_deps=true when dependency order changes" do
test_dir("two_sources")
File.open("sources", "wb") do |fh|
fh.write("one.o two.o")
end
result = run_test(rsconsfile: "cache_strict_deps.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to include "gcc -o program.exe one.o two.o"
result = run_test(rsconsfile: "cache_strict_deps.rb")
expect(result.stderr).to eq ""
expect(result.stdout).to eq ""
File.open("sources", "wb") do |fh|
fh.write("two.o one.o")
end
result = run_test(rsconsfile: "cache_strict_deps.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to include "gcc -o program.exe one.o two.o"
end
it "forces a rebuild when there is a new user dependency" do
test_dir("simple")
File.open("foo", "wb") {|fh| fh.write("hi")}
File.open("user_deps", "wb") {|fh| fh.write("")}
result = run_test(rsconsfile: "cache_user_dep.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"CC simple.o",
"LD simple.exe",
]
File.open("user_deps", "wb") {|fh| fh.write("foo")}
result = run_test(rsconsfile: "cache_user_dep.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"LD simple.exe",
]
end
it "forces a rebuild when a user dependency file checksum has changed" do
test_dir("simple")
File.open("foo", "wb") {|fh| fh.write("hi")}
File.open("user_deps", "wb") {|fh| fh.write("foo")}
result = run_test(rsconsfile: "cache_user_dep.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"CC simple.o",
"LD simple.exe",
]
result = run_test(rsconsfile: "cache_user_dep.rb")
expect(result.stderr).to eq ""
expect(result.stdout).to eq ""
File.open("foo", "wb") {|fh| fh.write("hi2")}
result = run_test(rsconsfile: "cache_user_dep.rb")
expect(result.stderr).to eq ""
expect(lines(result.stdout)).to eq [
"LD simple.exe",
]
end
end
end

View File

@ -13,194 +13,6 @@ module Rscons
end
end
describe "#initialize" do
context "when corrupt" do
it "prints a warning and defaults to an empty hash" do
expect(JSON).to receive(:load).and_return("string")
expect($stderr).to receive(:puts).with(/Warning:.*was.corrupt/)
c = Cache.instance
c.send(:initialize!)
expect(c.instance_variable_get(:@cache).is_a?(Hash)).to be_truthy
end
end
end
describe "#clear" do
it "removes the cache file" do
expect(FileUtils).to receive(:rm_f).with(Cache::CACHE_FILE)
allow(JSON).to receive(:load) {{}}
Cache.instance.clear
end
end
describe "#write" do
it "fills in 'version' and write to file" do
cache = {}
fh = $stdout
expect(fh).to receive(:puts)
expect(File).to receive(:open).and_yield(fh)
build_from(cache).write
expect(cache["version"]).to eq Rscons::VERSION
end
end
describe "#up_to_date?" do
empty_env = "env"
before do
allow(empty_env).to receive(:get_user_deps) { nil }
end
it "returns false when target file does not exist" do
expect(File).to receive(:exists?).with("target").and_return(false)
expect(build_from({}).up_to_date?("target", "command", [], empty_env)).to be_falsey
end
it "returns false when target is not registered in the cache" do
expect(File).to receive(:exists?).with("target").and_return(true)
expect(build_from({}).up_to_date?("target", "command", [], empty_env)).to be_falsey
end
it "returns false when the target's checksum does not match" do
_cache = {"targets" => {"target" => {"checksum" => "abc"}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("def")
expect(cache.up_to_date?("target", "command", [], empty_env)).to be_falsey
end
it "returns false when the build command has changed" do
_cache = {"targets" => {"target" => {"checksum" => "abc", "command" => Digest::MD5.hexdigest("old command".inspect)}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache.up_to_date?("target", "command", [], empty_env)).to be_falsey
end
it "returns false when there is a new dependency" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1"}]}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env)).to be_falsey
end
it "returns false when a dependency's checksum has changed" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1",
"checksum" => "dep.1.chk"},
{"fname" => "dep.2",
"checksum" => "dep.2.chk"},
{"fname" => "extra.dep",
"checksum" => "extra.dep.chk"}],
"user_deps" => []}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache).to receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
expect(cache).to receive(:calculate_checksum).with("dep.2").and_return("dep.2.changed")
expect(cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env)).to be_falsey
end
it "returns false with strict_deps=true when cache has an extra dependency" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1",
"checksum" => "dep.1.chk"},
{"fname" => "dep.2",
"checksum" => "dep.2.chk"},
{"fname" => "extra.dep",
"checksum" => "extra.dep.chk"}],
"user_deps" => []}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env, strict_deps: true)).to be_falsey
end
it "returns false when there is a new user dependency" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1"}],
"user_deps" => []}}}
cache = build_from(_cache)
env = "env"
expect(env).to receive(:get_user_deps).with("target").and_return(["file.ld"])
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache.up_to_date?("target", "command", ["dep.1"], env)).to be_falsey
end
it "returns false when a user dependency checksum has changed" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1",
"checksum" => "dep.1.chk"},
{"fname" => "dep.2",
"checksum" => "dep.2.chk"},
{"fname" => "extra.dep",
"checksum" => "extra.dep.chk"}],
"user_deps" => [{"fname" => "user.dep",
"checksum" => "user.dep.chk"}]}}}
cache = build_from(_cache)
env = "env"
expect(env).to receive(:get_user_deps).with("target").and_return(["user.dep"])
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache).to receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
expect(cache).to receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk")
expect(cache).to receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk")
expect(cache).to receive(:calculate_checksum).with("user.dep").and_return("INCORRECT")
expect(cache.up_to_date?("target", "command", ["dep.1", "dep.2"], env)).to be_falsey
end
it "returns true when no condition for false is met" do
_cache = {"targets" => {"target" => {"checksum" => "abc",
"command" => Digest::MD5.hexdigest("command".inspect),
"deps" => [{"fname" => "dep.1",
"checksum" => "dep.1.chk"},
{"fname" => "dep.2",
"checksum" => "dep.2.chk"},
{"fname" => "extra.dep",
"checksum" => "extra.dep.chk"}],
"user_deps" => []}}}
cache = build_from(_cache)
expect(File).to receive(:exists?).with("target").and_return(true)
expect(cache).to receive(:calculate_checksum).with("target").and_return("abc")
expect(cache).to receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
expect(cache).to receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk")
expect(cache).to receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk")
expect(cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env)).to be_truthy
end
end
describe "#register_build" do
it "stores the given information in the cache" do
_cache = {}
cache = build_from(_cache)
env = "env"
expect(env).to receive(:get_user_deps).with("the target").and_return(["user.dep"])
expect(cache).to receive(:calculate_checksum).with("the target").and_return("the checksum")
expect(cache).to receive(:calculate_checksum).with("dep 1").and_return("dep 1 checksum")
expect(cache).to receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum")
expect(cache).to receive(:calculate_checksum).with("user.dep").and_return("user.dep checksum")
cache.register_build("the target", "the command", ["dep 1", "dep 2"], env)
cached_target = cache.instance_variable_get(:@cache)["targets"]["the target"]
expect(cached_target).to_not be_nil
expect(cached_target["command"]).to eq Digest::MD5.hexdigest("the command".inspect)
expect(cached_target["checksum"]).to eq "the checksum"
expect(cached_target["deps"]).to eq [
{"fname" => "dep 1", "checksum" => "dep 1 checksum"},
{"fname" => "dep 2", "checksum" => "dep 2 checksum"},
]
expect(cached_target["user_deps"]).to eq [
{"fname" => "user.dep", "checksum" => "user.dep checksum"},
]
end
end
describe "#targets" do
it "returns a list of targets that are cached" do
cache = {"targets" => {"t1" => {}, "t2" => {}, "t3" => {}}}