rscons 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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