rscons 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -86,7 +86,7 @@ module Rscons
86
86
  env.add_builder(builder)
87
87
  end
88
88
  end
89
- env.append(@varset.clone) if clone.include?(:variables)
89
+ env.append(@varset) if clone.include?(:variables)
90
90
  env.build_root = @build_root if clone.include?(:build_root)
91
91
  if clone.include?(:build_dirs)
92
92
  @build_dirs.each do |src_dir, obj_dir|
@@ -164,38 +164,44 @@ module Rscons
164
164
  # Add a set of construction variables or environment options.
165
165
  # @see VarSet#append
166
166
  def append(*args)
167
- @varset.send(:append, *args)
167
+ @varset.append(*args)
168
168
  end
169
169
 
170
170
  # Build all target specified in the Environment.
171
171
  # When a block is passed to Environment.new, this method is automatically
172
172
  # called after the block returns.
173
173
  def process
174
- cache = Cache.new
175
- targets_processed = {}
176
- process_target = proc do |target|
177
- targets_processed[target] ||= begin
178
- @targets[target][:source].each do |src|
179
- if @targets.include?(src) and not targets_processed.include?(src)
180
- process_target.call(src)
174
+ unless @targets.empty?
175
+ clean_target_paths!
176
+ cache = Cache.instance
177
+ cache.clear_checksum_cache!
178
+ targets_processed = {}
179
+ process_target = proc do |target|
180
+ targets_processed[target] ||= begin
181
+ @targets[target][:sources].each do |src|
182
+ if @targets.include?(src) and not targets_processed.include?(src)
183
+ process_target.call(src)
184
+ end
181
185
  end
186
+ result = run_builder(@targets[target][:builder],
187
+ target,
188
+ @targets[target][:sources],
189
+ cache,
190
+ @targets[target][:vars] || {})
191
+ unless result
192
+ raise BuildError.new("Failed to build #{target}")
193
+ end
194
+ result
182
195
  end
183
- result = run_builder(@targets[target][:builder],
184
- target,
185
- @targets[target][:source],
186
- cache,
187
- @targets[target][:vars] || {})
188
- unless result
189
- cache.write
190
- raise BuildError.new("Failed to build #{target}")
196
+ end
197
+ begin
198
+ @targets.each do |target, target_params|
199
+ process_target.call(target)
191
200
  end
192
- result
201
+ ensure
202
+ cache.write
193
203
  end
194
204
  end
195
- @targets.each do |target, info|
196
- process_target.call(target)
197
- end
198
- cache.write
199
205
  end
200
206
 
201
207
  # Clear all targets registered for the Environment.
@@ -246,25 +252,28 @@ module Rscons
246
252
  end
247
253
  end
248
254
 
249
- alias_method :orig_method_missing, :method_missing
250
255
  def method_missing(method, *args)
251
256
  if @builders.has_key?(method.to_s)
252
- target, source, vars, *rest = args
257
+ target, sources, vars, *rest = args
253
258
  unless vars.nil? or vars.is_a?(Hash) or vars.is_a?(VarSet)
254
259
  raise "Unexpected construction variable set: #{vars.inspect}"
255
260
  end
256
- source = [source] unless source.is_a?(Array)
257
- @targets[target] = {
258
- builder: @builders[method.to_s],
259
- source: source,
260
- vars: vars,
261
- args: rest,
262
- }
261
+ sources = [sources] unless sources.is_a?(Array)
262
+ add_target(target, @builders[method.to_s], sources, vars, rest)
263
263
  else
264
- orig_method_missing(method, *args)
264
+ super
265
265
  end
266
266
  end
267
267
 
268
+ def add_target(target, builder, sources, vars, args)
269
+ @targets[target] = {
270
+ builder: builder,
271
+ sources: sources,
272
+ vars: vars,
273
+ args: args,
274
+ }
275
+ end
276
+
268
277
  # Manually record a given target as depending on the specified
269
278
  # dependency files.
270
279
  def depends(target, *user_deps)
@@ -321,12 +330,34 @@ module Rscons
321
330
  target: target,
322
331
  sources: sources,
323
332
  vars: vars,
333
+ env: self,
324
334
  }
325
335
  build_hook_block.call(build_operation)
326
336
  end
327
337
  builder.run(target, sources, cache, self, vars)
328
338
  end
329
339
 
340
+ private
341
+
342
+ # Expand all target paths that begin with ^/ to be relative to the
343
+ # Environment's build root, if present
344
+ def clean_target_paths!
345
+ if @build_root
346
+ expand = lambda do |path|
347
+ path.sub(%r{^\^(?=[\\/])}, @build_root)
348
+ end
349
+
350
+ new_targets = {}
351
+ @targets.each_pair do |target, target_params|
352
+ target_params[:sources].map! do |source|
353
+ expand[source]
354
+ end
355
+ new_targets[expand[target]] = target_params
356
+ end
357
+ @targets = new_targets
358
+ end
359
+ end
360
+
330
361
  # Parse dependencies for a given target from a Makefile.
331
362
  # This method is used internally by Rscons builders.
332
363
  # @param mf_fname [String] File name of the Makefile to read.
@@ -1,45 +1,73 @@
1
1
  module Rscons
2
2
  # This class represents a collection of variables which can be accessed
3
- # as certain types
3
+ # as certain types.
4
+ # Only nil, strings, arrays, and hashes should be stored in a VarSet.
4
5
  class VarSet
5
- # The underlying hash
6
- attr_reader :vars
7
-
8
- # Create a VarSet
6
+ # Create a VarSet.
9
7
  # @param vars [Hash] Optional initial variables.
10
8
  def initialize(vars = {})
11
- if vars.is_a?(VarSet)
12
- @vars = vars.clone.vars
13
- else
14
- @vars = vars
15
- end
9
+ @my_vars = {}
10
+ @coa_vars = []
11
+ append(vars)
16
12
  end
17
13
 
18
14
  # Access the value of variable as a particular type
19
15
  # @param key [String, Symbol] The variable name.
16
+ # @return [Object] The variable's value.
20
17
  def [](key)
21
- @vars[key]
18
+ if @my_vars.include?(key)
19
+ @my_vars[key]
20
+ else
21
+ @coa_vars.each do |coa_vars|
22
+ if coa_vars.include?(key)
23
+ @my_vars[key] = deep_dup(coa_vars[key])
24
+ return @my_vars[key]
25
+ end
26
+ end
27
+ nil
28
+ end
22
29
  end
23
30
 
24
31
  # Assign a value to a variable.
25
32
  # @param key [String, Symbol] The variable name.
26
- # @param val [Object] The value.
33
+ # @param val [Object] The value to set.
27
34
  def []=(key, val)
28
- @vars[key] = val
35
+ @my_vars[key] = val
36
+ end
37
+
38
+ # Check if the VarSet contains a variable.
39
+ # @param key [String, Symbol] The variable name.
40
+ # @return [true, false] Whether the VarSet contains a variable.
41
+ def include?(key)
42
+ if @my_vars.include?(key)
43
+ true
44
+ else
45
+ @coa_vars.find do |coa_vars|
46
+ coa_vars.include?(key)
47
+ end
48
+ end
29
49
  end
30
50
 
31
51
  # Add or overwrite a set of variables
32
52
  # @param values [VarSet, Hash] New set of variables.
33
53
  def append(values)
34
- values = values.vars if values.is_a?(VarSet)
35
- @vars.merge!(Marshal.load(Marshal.dump(values)))
54
+ coa!
55
+ if values.is_a?(VarSet)
56
+ values.send(:coa!)
57
+ @coa_vars = values.instance_variable_get(:@coa_vars) + @coa_vars
58
+ else
59
+ @my_vars = deep_dup(values)
60
+ end
36
61
  self
37
62
  end
38
63
 
39
64
  # Create a new VarSet object based on the first merged with other.
40
65
  # @param other [VarSet, Hash] Other variables to add or overwrite.
41
66
  def merge(other = {})
42
- VarSet.new(Marshal.load(Marshal.dump(@vars))).append(other)
67
+ coa!
68
+ varset = self.class.new
69
+ varset.instance_variable_set(:@coa_vars, @coa_vars.dup)
70
+ varset.append(other)
43
71
  end
44
72
  alias_method :clone, :merge
45
73
 
@@ -54,18 +82,47 @@ module Rscons
54
82
  else
55
83
  if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
56
84
  prefix, varname, suffix = $1, $2, $3
57
- varval = expand_varref(@vars[varname])
85
+ varval = expand_varref(self[varname])
58
86
  if varval.is_a?(String)
59
87
  expand_varref("#{prefix}#{varval}#{suffix}")
60
88
  elsif varval.is_a?(Array)
61
89
  varval.map {|vv| expand_varref("#{prefix}#{vv}#{suffix}")}.flatten
62
90
  else
63
- raise "I do not know how to expand a variable reference to a #{varval.class.name} (from #{varname.inspect} => #{@vars[varname].inspect})"
91
+ raise "I do not know how to expand a variable reference to a #{varval.class.name} (from #{varname.inspect} => #{self[varname].inspect})"
64
92
  end
65
93
  else
66
94
  varref
67
95
  end
68
96
  end
69
97
  end
98
+
99
+ private
100
+
101
+ # Move all VarSet variables into the copy-on-access list.
102
+ def coa!
103
+ unless @my_vars.empty?
104
+ @coa_vars.unshift(@my_vars)
105
+ @my_vars = {}
106
+ end
107
+ end
108
+
109
+ # Create a deep copy of an object.
110
+ # @param obj [nil, String, Array, Hash] Object to deep copy.
111
+ # @return [nil, String, Array, Hash] Deep copied value.
112
+ def deep_dup(obj)
113
+ obj_class = obj.class
114
+ if obj_class == Hash
115
+ obj.reduce({}) do |result, (k, v)|
116
+ result[k] = deep_dup(v)
117
+ result
118
+ end
119
+ elsif obj_class == Array
120
+ obj.map { |v| deep_dup(v) }
121
+ elsif obj_class == String
122
+ obj.dup
123
+ else
124
+ obj
125
+ end
126
+ end
70
127
  end
71
128
  end
@@ -1,4 +1,4 @@
1
1
  module Rscons
2
2
  # gem version
3
- VERSION = "1.3.0"
3
+ VERSION = "1.4.0"
4
4
  end
@@ -1,5 +1,14 @@
1
1
  require 'fileutils'
2
2
 
3
+ class Dir
4
+ class << self
5
+ alias_method :orig_bracket, :[]
6
+ end
7
+ def self.[](*args)
8
+ orig_bracket(*args).sort
9
+ end
10
+ end
11
+
3
12
  describe Rscons do
4
13
  BUILD_TEST_RUN_DIR = "build_test_run"
5
14
 
@@ -180,6 +189,23 @@ describe Rscons do
180
189
  lines.should == ["CC build_root/src/one/one.o", "CC build_root/src/two/two.o", "LD build_dir"]
181
190
  end
182
191
 
192
+ it "expands target and source paths starting with ^/ to be relative to the build root" do
193
+ test_dir('build_dir')
194
+ Rscons::Environment.new(echo: :command) do |env|
195
+ env.append('CPPPATH' => Dir['src/**/*/'])
196
+ env.build_root = "build_root"
197
+ FileUtils.mkdir_p(env.build_root)
198
+ FileUtils.mv("src/one/one.c", "build_root")
199
+ env.Object("^/one.o", "^/one.c")
200
+ env.Program('build_dir', Dir['src/**/*.c'] + ["^/one.o"])
201
+ end
202
+ lines.should == [
203
+ %q{gcc -c -o build_root/one.o -MMD -MF build_root/one.mf -Isrc/one/ -Isrc/two/ build_root/one.c},
204
+ %q{gcc -c -o build_root/src/two/two.o -MMD -MF build_root/src/two/two.mf -Isrc/one/ -Isrc/two/ src/two/two.c},
205
+ %q{gcc -o build_dir build_root/src/two/two.o build_root/one.o},
206
+ ]
207
+ end
208
+
183
209
  it 'cleans built files' do
184
210
  test_dir('build_dir')
185
211
  Rscons::Environment.new do |env|
@@ -428,4 +454,34 @@ EOF
428
454
  `./hello-d`.rstrip.should == "Hello from D!"
429
455
  end
430
456
  end
457
+
458
+ it "supports disassembling object files" do
459
+ test_dir("simple")
460
+ Rscons::Environment.new do |env|
461
+ env.Object("simple.o", "simple.c")
462
+ env.Disassemble("simple.txt", "simple.o")
463
+ end
464
+ File.exists?("simple.txt").should be_true
465
+ File.read("simple.txt").should =~ /Disassembly of section .text:/
466
+ end
467
+
468
+ it "supports preprocessing C sources" do
469
+ test_dir("simple")
470
+ Rscons::Environment.new do |env|
471
+ env.Preprocess("simplepp.c", "simple.c")
472
+ env.Program("simple", "simplepp.c")
473
+ end
474
+ File.read("simplepp.c").should =~ /# \d+ "simple.c"/
475
+ `./simple`.should == "This is a simple C program\n"
476
+ end
477
+
478
+ it "supports preprocessing C++ sources" do
479
+ test_dir("simple_cc")
480
+ Rscons::Environment.new do |env|
481
+ env.Preprocess("simplepp.cc", "simple.cc")
482
+ env.Program("simple", "simplepp.cc")
483
+ end
484
+ File.read("simplepp.cc").should =~ /# \d+ "simple.cc"/
485
+ `./simple`.should == "This is a simple C++ program\n"
486
+ end
431
487
  end
@@ -0,0 +1,23 @@
1
+ module Rscons
2
+ module Builders
3
+ describe CFile do
4
+ let(:env) {Environment.new}
5
+ subject {CFile.new}
6
+
7
+ it "invokes bison to create a .c file from a .y file" do
8
+ subject.should_receive(:standard_build).with("YACC parser.c", "parser.c", ["bison", "-d", "-o", "parser.c", "parser.y"], ["parser.y"], env, :cache)
9
+ subject.run("parser.c", ["parser.y"], :cache, env, {})
10
+ end
11
+
12
+ it "invokes a custom lexer to create a .cc file from a .ll file" do
13
+ env["LEX"] = "custom_lex"
14
+ subject.should_receive(:standard_build).with("LEX lexer.cc", "lexer.cc", ["custom_lex", "-o", "lexer.cc", "parser.ll"], ["parser.ll"], env, :cache)
15
+ subject.run("lexer.cc", ["parser.ll"], :cache, env, {})
16
+ end
17
+
18
+ it "raises an error when an unknown source file is specified" do
19
+ expect {subject.run("file.c", ["foo.bar"], :cache, env, {})}.to raise_error /Unknown source file .foo.bar. for CFile builder/
20
+ end
21
+ end
22
+ end
23
+ end
@@ -5,35 +5,42 @@ module Rscons
5
5
  end
6
6
 
7
7
  def build_from(cache)
8
- YAML.should_receive(:load).and_return(cache)
9
- Cache.new
10
- end
11
-
12
- describe ".clear" do
13
- it "removes the cache file" do
14
- FileUtils.should_receive(:rm_f).with(Cache::CACHE_FILE)
15
- Cache.clear
8
+ JSON.stub(:load) do
9
+ cache
10
+ end
11
+ Cache.instance.tap do |cache|
12
+ cache.send(:initialize!)
16
13
  end
17
14
  end
18
15
 
19
16
  describe "#initialize" do
20
17
  context "when corrupt" do
21
18
  it "prints a warning and defaults to an empty hash" do
22
- YAML.should_receive(:load).and_return("string")
19
+ JSON.should_receive(:load).and_return("string")
23
20
  $stderr.should_receive(:puts).with(/Warning:.*was.corrupt/)
24
- Cache.new.instance_variable_get(:@cache).is_a?(Hash).should be_true
21
+ c = Cache.instance
22
+ c.send(:initialize!)
23
+ c.instance_variable_get(:@cache).is_a?(Hash).should be_true
25
24
  end
26
25
  end
27
26
  end
28
27
 
28
+ describe "#clear" do
29
+ it "removes the cache file" do
30
+ FileUtils.should_receive(:rm_f).with(Cache::CACHE_FILE)
31
+ JSON.stub(:load) {{}}
32
+ Cache.instance.clear
33
+ end
34
+ end
35
+
29
36
  describe "#write" do
30
- it "should fill in :version and write to file" do
37
+ it "should fill in 'version' and write to file" do
31
38
  cache = {}
32
39
  fh = $stdout
33
40
  fh.should_receive(:puts)
34
41
  File.should_receive(:open).and_yield(fh)
35
42
  build_from(cache).write
36
- cache[:version].should == Rscons::VERSION
43
+ cache["version"].should == Rscons::VERSION
37
44
  end
38
45
  end
39
46
 
@@ -54,7 +61,7 @@ module Rscons
54
61
  end
55
62
 
56
63
  it "returns false when the target's checksum does not match" do
57
- _cache = {targets: {"target" => {checksum: "abc"}}}
64
+ _cache = {"targets" => {"target" => {"checksum" => "abc"}}}
58
65
  cache = build_from(_cache)
59
66
  File.should_receive(:exists?).with("target").and_return(true)
60
67
  cache.should_receive(:calculate_checksum).with("target").and_return("def")
@@ -62,7 +69,7 @@ module Rscons
62
69
  end
63
70
 
64
71
  it "returns false when the build command has changed" do
65
- _cache = {targets: {"target" => {checksum: "abc", command: "old command"}}}
72
+ _cache = {"targets" => {"target" => {"checksum" => "abc", "command" => Digest::MD5.hexdigest("old command".inspect)}}}
66
73
  cache = build_from(_cache)
67
74
  File.should_receive(:exists?).with("target").and_return(true)
68
75
  cache.should_receive(:calculate_checksum).with("target").and_return("abc")
@@ -70,9 +77,9 @@ module Rscons
70
77
  end
71
78
 
72
79
  it "returns false when there is a new dependency" do
73
- _cache = {targets: {"target" => {checksum: "abc",
74
- command: "command",
75
- deps: [{fname: "dep.1"}]}}}
80
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
81
+ "command" => Digest::MD5.hexdigest("command".inspect),
82
+ "deps" => [{"fname" => "dep.1"}]}}}
76
83
  cache = build_from(_cache)
77
84
  File.should_receive(:exists?).with("target").and_return(true)
78
85
  cache.should_receive(:calculate_checksum).with("target").and_return("abc")
@@ -80,15 +87,15 @@ module Rscons
80
87
  end
81
88
 
82
89
  it "returns false when a dependency's checksum has changed" do
83
- _cache = {targets: {"target" => {checksum: "abc",
84
- command: "command",
85
- deps: [{fname: "dep.1",
86
- checksum: "dep.1.chk"},
87
- {fname: "dep.2",
88
- checksum: "dep.2.chk"},
89
- {fname: "extra.dep",
90
- checksum: "extra.dep.chk"}],
91
- user_deps: []}}}
90
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
91
+ "command" => Digest::MD5.hexdigest("command".inspect),
92
+ "deps" => [{"fname" => "dep.1",
93
+ "checksum" => "dep.1.chk"},
94
+ {"fname" => "dep.2",
95
+ "checksum" => "dep.2.chk"},
96
+ {"fname" => "extra.dep",
97
+ "checksum" => "extra.dep.chk"}],
98
+ "user_deps" => []}}}
92
99
  cache = build_from(_cache)
93
100
  File.should_receive(:exists?).with("target").and_return(true)
94
101
  cache.should_receive(:calculate_checksum).with("target").and_return("abc")
@@ -98,15 +105,15 @@ module Rscons
98
105
  end
99
106
 
100
107
  it "returns false with strict_deps=true when cache has an extra dependency" do
101
- _cache = {targets: {"target" => {checksum: "abc",
102
- command: "command",
103
- deps: [{fname: "dep.1",
104
- checksum: "dep.1.chk"},
105
- {fname: "dep.2",
106
- checksum: "dep.2.chk"},
107
- {fname: "extra.dep",
108
- checksum: "extra.dep.chk"}],
109
- user_deps: []}}}
108
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
109
+ "command" => Digest::MD5.hexdigest("command".inspect),
110
+ "deps" => [{"fname" => "dep.1",
111
+ "checksum" => "dep.1.chk"},
112
+ {"fname" => "dep.2",
113
+ "checksum" => "dep.2.chk"},
114
+ {"fname" => "extra.dep",
115
+ "checksum" => "extra.dep.chk"}],
116
+ "user_deps" => []}}}
110
117
  cache = build_from(_cache)
111
118
  File.should_receive(:exists?).with("target").and_return(true)
112
119
  cache.should_receive(:calculate_checksum).with("target").and_return("abc")
@@ -114,10 +121,10 @@ module Rscons
114
121
  end
115
122
 
116
123
  it "returns false when there is a new user dependency" do
117
- _cache = {targets: {"target" => {checksum: "abc",
118
- command: "command",
119
- deps: [{fname: "dep.1"}],
120
- user_deps: []}}}
124
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
125
+ "command" => Digest::MD5.hexdigest("command".inspect),
126
+ "deps" => [{"fname" => "dep.1"}],
127
+ "user_deps" => []}}}
121
128
  cache = build_from(_cache)
122
129
  env = "env"
123
130
  env.should_receive(:get_user_deps).with("target").and_return(["file.ld"])
@@ -127,16 +134,16 @@ module Rscons
127
134
  end
128
135
 
129
136
  it "returns false when a user dependency checksum has changed" do
130
- _cache = {targets: {"target" => {checksum: "abc",
131
- command: "command",
132
- deps: [{fname: "dep.1",
133
- checksum: "dep.1.chk"},
134
- {fname: "dep.2",
135
- checksum: "dep.2.chk"},
136
- {fname: "extra.dep",
137
- checksum: "extra.dep.chk"}],
138
- user_deps: [{fname: "user.dep",
139
- checksum: "user.dep.chk"}]}}}
137
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
138
+ "command" => Digest::MD5.hexdigest("command".inspect),
139
+ "deps" => [{"fname" => "dep.1",
140
+ "checksum" => "dep.1.chk"},
141
+ {"fname" => "dep.2",
142
+ "checksum" => "dep.2.chk"},
143
+ {"fname" => "extra.dep",
144
+ "checksum" => "extra.dep.chk"}],
145
+ "user_deps" => [{"fname" => "user.dep",
146
+ "checksum" => "user.dep.chk"}]}}}
140
147
  cache = build_from(_cache)
141
148
  env = "env"
142
149
  env.should_receive(:get_user_deps).with("target").and_return(["user.dep"])
@@ -150,15 +157,15 @@ module Rscons
150
157
  end
151
158
 
152
159
  it "returns true when no condition for false is met" do
153
- _cache = {targets: {"target" => {checksum: "abc",
154
- command: "command",
155
- deps: [{fname: "dep.1",
156
- checksum: "dep.1.chk"},
157
- {fname: "dep.2",
158
- checksum: "dep.2.chk"},
159
- {fname: "extra.dep",
160
- checksum: "extra.dep.chk"}],
161
- user_deps: []}}}
160
+ _cache = {"targets" => {"target" => {"checksum" => "abc",
161
+ "command" => Digest::MD5.hexdigest("command".inspect),
162
+ "deps" => [{"fname" => "dep.1",
163
+ "checksum" => "dep.1.chk"},
164
+ {"fname" => "dep.2",
165
+ "checksum" => "dep.2.chk"},
166
+ {"fname" => "extra.dep",
167
+ "checksum" => "extra.dep.chk"}],
168
+ "user_deps" => []}}}
162
169
  cache = build_from(_cache)
163
170
  File.should_receive(:exists?).with("target").and_return(true)
164
171
  cache.should_receive(:calculate_checksum).with("target").and_return("abc")
@@ -180,23 +187,23 @@ module Rscons
180
187
  cache.should_receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum")
181
188
  cache.should_receive(:calculate_checksum).with("user.dep").and_return("user.dep checksum")
182
189
  cache.register_build("the target", "the command", ["dep 1", "dep 2"], env)
183
- cached_target = cache.instance_variable_get(:@cache)[:targets]["the target"]
190
+ cached_target = cache.instance_variable_get(:@cache)["targets"]["the target"]
184
191
  cached_target.should_not be_nil
185
- cached_target[:command].should == "the command"
186
- cached_target[:checksum].should == "the checksum"
187
- cached_target[:deps].should == [
188
- {fname: "dep 1", checksum: "dep 1 checksum"},
189
- {fname: "dep 2", checksum: "dep 2 checksum"},
192
+ cached_target["command"].should == Digest::MD5.hexdigest("the command".inspect)
193
+ cached_target["checksum"].should == "the checksum"
194
+ cached_target["deps"].should == [
195
+ {"fname" => "dep 1", "checksum" => "dep 1 checksum"},
196
+ {"fname" => "dep 2", "checksum" => "dep 2 checksum"},
190
197
  ]
191
- cached_target[:user_deps].should == [
192
- {fname: "user.dep", checksum: "user.dep checksum"},
198
+ cached_target["user_deps"].should == [
199
+ {"fname" => "user.dep", "checksum" => "user.dep checksum"},
193
200
  ]
194
201
  end
195
202
  end
196
203
 
197
204
  describe "#targets" do
198
205
  it "returns a list of targets that are cached" do
199
- cache = {targets: {"t1" => {}, "t2" => {}, "t3" => {}}}
206
+ cache = {"targets" => {"t1" => {}, "t2" => {}, "t3" => {}}}
200
207
  build_from(cache).targets.should == ["t1", "t2", "t3"]
201
208
  end
202
209
  end
@@ -218,11 +225,21 @@ module Rscons
218
225
  cache.mkdir_p("one\\two\\four")
219
226
  cache.directories.should == ["one/two", "one/two/three", "one/two/four"]
220
227
  end
228
+
229
+ it "handles absolute paths" do
230
+ _cache = {}
231
+ cache = build_from(_cache)
232
+ File.should_receive(:exists?).with("/one").and_return(true)
233
+ File.should_receive(:exists?).with("/one/two").and_return(false)
234
+ FileUtils.should_receive(:mkdir).with("/one/two")
235
+ cache.mkdir_p("/one/two")
236
+ cache.directories.should == ["/one/two"]
237
+ end
221
238
  end
222
239
 
223
240
  describe "#directories" do
224
241
  it "returns a list of directories that are cached" do
225
- _cache = {directories: {"dir1" => true, "dir2" => true}}
242
+ _cache = {"directories" => {"dir1" => true, "dir2" => true}}
226
243
  build_from(_cache).directories.should == ["dir1", "dir2"]
227
244
  end
228
245
  end