autoc 1.2 → 1.3
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.
- checksums.yaml +4 -4
- data/CHANGES +4 -0
- data/README +3 -1
- data/doc/AutoC.html +23 -7
- data/doc/AutoC/Code.html +3 -3
- data/doc/AutoC/Collection.html +289 -76
- data/doc/AutoC/HashMap.html +44 -46
- data/doc/AutoC/HashSet.html +20 -17
- data/doc/AutoC/List.html +56 -92
- data/doc/AutoC/Module.html +2 -2
- data/doc/AutoC/Module/File.html +2 -2
- data/doc/AutoC/Module/Header.html +6 -4
- data/doc/AutoC/Module/Source.html +26 -26
- data/doc/AutoC/Priority.html +2 -2
- data/doc/AutoC/Queue.html +30 -92
- data/doc/AutoC/Reference.html +217 -61
- data/doc/AutoC/String.html +1393 -0
- data/doc/AutoC/Type.html +240 -128
- data/doc/AutoC/UserDefinedType.html +688 -47
- data/doc/AutoC/Vector.html +154 -62
- data/doc/_index.html +9 -2
- data/doc/class_list.html +1 -1
- data/doc/file.CHANGES.html +10 -2
- data/doc/file.README.html +5 -3
- data/doc/index.html +5 -3
- data/doc/method_list.html +235 -97
- data/doc/top-level-namespace.html +2 -2
- data/lib/autoc.rb +3 -1
- data/lib/autoc/code.rb +3 -2
- data/lib/autoc/collection.rb +36 -40
- data/lib/autoc/collection/hash_map.rb +10 -14
- data/lib/autoc/collection/hash_set.rb +12 -11
- data/lib/autoc/collection/list.rb +21 -11
- data/lib/autoc/collection/queue.rb +5 -8
- data/lib/autoc/collection/vector.rb +28 -12
- data/lib/autoc/string.rb +492 -0
- data/lib/autoc/type.rb +155 -66
- data/test/test.rb +157 -35
- data/test/test_char_string.rb +270 -0
- data/test/test_int_list.rb +35 -0
- data/test/test_int_vector.rb +34 -0
- data/test/test_value_hash_map.rb +162 -0
- data/test/test_value_hash_set.rb +173 -0
- data/test/test_value_list.rb +193 -0
- data/test/test_value_queue.rb +275 -0
- data/test/test_value_vector.rb +155 -0
- data/test/value.rb +80 -0
- metadata +15 -8
- data/test/test.c +0 -1041
- data/test/test.h +0 -41
- data/test/test_auto.c +0 -3407
- data/test/test_auto.h +0 -765
data/lib/autoc/type.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require "set"
|
2
1
|
require "forwardable"
|
3
2
|
require "autoc/code"
|
4
3
|
|
@@ -24,9 +23,10 @@ class Dispatcher
|
|
24
23
|
def ===(other) other.is_a?(ParameterArray) && types == other.types end
|
25
24
|
def types; collect {|x| x.first} end
|
26
25
|
def names; collect {|x| x.last} end
|
27
|
-
def pass; names.join(
|
28
|
-
|
29
|
-
def
|
26
|
+
def pass; names.join(",") end
|
27
|
+
# ANSI C instructs the empty parameter list to be marked as `void`
|
28
|
+
def declaration; empty? ? :void : types.join(",") end
|
29
|
+
def definition; empty? ? :void : collect {|x| "#{x.first} #{x.last}"}.join(",") end
|
30
30
|
end # ParameterArray
|
31
31
|
|
32
32
|
# def call(*params)
|
@@ -106,10 +106,12 @@ class Type < Code
|
|
106
106
|
def write_intf(stream)
|
107
107
|
stream << %$
|
108
108
|
#ifndef AUTOC_INLINE
|
109
|
-
#
|
110
|
-
#define AUTOC_INLINE __inline
|
109
|
+
#if defined(_MSC_VER) || defined(__DMC__)
|
110
|
+
#define AUTOC_INLINE AUTOC_STATIC __inline
|
111
|
+
#elif defined(__LCC__)
|
112
|
+
#define AUTOC_INLINE AUTOC_STATIC /* LCC rejects static __inline */
|
111
113
|
#elif __STDC_VERSION__ >= 199901L
|
112
|
-
#define AUTOC_INLINE inline
|
114
|
+
#define AUTOC_INLINE AUTOC_STATIC inline
|
113
115
|
#else
|
114
116
|
#define AUTOC_INLINE AUTOC_STATIC
|
115
117
|
#endif
|
@@ -122,7 +124,7 @@ class Type < Code
|
|
122
124
|
#endif
|
123
125
|
#endif
|
124
126
|
#ifndef AUTOC_STATIC
|
125
|
-
#
|
127
|
+
#if defined(_MSC_VER)
|
126
128
|
#define AUTOC_STATIC __pragma(warning(suppress:4100)) static
|
127
129
|
#elif defined(__GNUC__)
|
128
130
|
#define AUTOC_STATIC __attribute__((__used__)) static
|
@@ -161,7 +163,7 @@ class Type < Code
|
|
161
163
|
|
162
164
|
def prefix
|
163
165
|
# Lazy evaluator for simple types like char* which do not actually use
|
164
|
-
# this method and hence do not require the prefix to be valid C identifier
|
166
|
+
# this method and hence do not require the prefix to be a valid C identifier
|
165
167
|
AutoC.c_id(type)
|
166
168
|
end
|
167
169
|
|
@@ -169,20 +171,27 @@ class Type < Code
|
|
169
171
|
@type = type.to_s
|
170
172
|
@type_ref = "#{self.type}*"
|
171
173
|
@visibility = [:public, :private, :static].include?(visibility) ? visibility : raise("unsupported visibility")
|
172
|
-
@capability = Set[:constructible, :destructible, :copyable, :comparable, :hashable, :orderable] # Can be used to disable specific capabilities for a type
|
173
174
|
# Canonic special method signatures
|
174
|
-
@
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
175
|
+
@signature = {
|
176
|
+
:ctor => Function::Signature.new([type^:self]),
|
177
|
+
:dtor => Function::Signature.new([type^:self]),
|
178
|
+
:copy => Function::Signature.new([type^:dst, type^:src]),
|
179
|
+
:equal => Function::Signature.new([type^:lt, type^:rt], :int),
|
180
|
+
:identify => Function::Signature.new([type^:self], :size_t),
|
181
|
+
:less => Function::Signature.new([type^:lt, type^:rt], :int),
|
182
|
+
}
|
180
183
|
end
|
181
184
|
|
182
185
|
def method_missing(method, *args)
|
183
186
|
str = method.to_s
|
184
187
|
str = str.sub(/[\!\?]$/, '') # Strip trailing ? or !
|
188
|
+
x = false # Have leading underscore
|
189
|
+
if /_(.*)/ =~ str
|
190
|
+
str = $1
|
191
|
+
x = true
|
192
|
+
end
|
185
193
|
fn = prefix + str[0,1].capitalize + str[1..-1] # Ruby 1.8 compatible
|
194
|
+
fn = "_" << fn if x # Carry over the leading underscore
|
186
195
|
if args.empty?
|
187
196
|
fn # Emit bare function name
|
188
197
|
elsif args.size == 1 && args.first == nil
|
@@ -217,27 +226,29 @@ class Type < Code
|
|
217
226
|
end
|
218
227
|
end
|
219
228
|
|
229
|
+
# Abstract methods which must be defined in descendant classes
|
230
|
+
|
220
231
|
# def write_intf_types(stream)
|
221
232
|
|
222
233
|
# def write_intf_decls(stream, declare, define)
|
223
234
|
|
224
235
|
# def write_impls(stream, define)
|
225
236
|
|
226
|
-
def extern;
|
237
|
+
def extern; :AUTOC_EXTERN end
|
227
238
|
|
228
|
-
def inline;
|
239
|
+
def inline; :AUTOC_INLINE end
|
229
240
|
|
230
|
-
def static;
|
241
|
+
def static; :AUTOC_STATIC end
|
231
242
|
|
232
|
-
def assert;
|
243
|
+
def assert; :assert end
|
233
244
|
|
234
|
-
def malloc;
|
245
|
+
def malloc; :malloc end
|
235
246
|
|
236
|
-
def calloc;
|
247
|
+
def calloc; :calloc end
|
237
248
|
|
238
|
-
def free;
|
249
|
+
def free; :free end
|
239
250
|
|
240
|
-
def abort;
|
251
|
+
def abort; :abort end
|
241
252
|
|
242
253
|
def public?; @visibility == :public end
|
243
254
|
|
@@ -245,17 +256,29 @@ class Type < Code
|
|
245
256
|
|
246
257
|
def static?; @visibility == :static end
|
247
258
|
|
248
|
-
|
259
|
+
# A generic type is not required to provide any special functions therefore all the
|
260
|
+
# availability methods below return false
|
261
|
+
|
262
|
+
# Returns *true* if the type provides a well-defined parameterless default type constructor
|
263
|
+
def constructible?; false end
|
249
264
|
|
250
|
-
|
265
|
+
# Returns *true* if the type provides a well-defined type constructor which can have extra arguments
|
266
|
+
def initializable?; false end
|
251
267
|
|
252
|
-
|
268
|
+
# Returns *true* if the type provides a well-defined type destructor
|
269
|
+
def destructible?; false end
|
253
270
|
|
254
|
-
|
271
|
+
# Returns *true* if the type provides a well-defined copy constructor to create a clone of an instance
|
272
|
+
def copyable?; false end
|
273
|
+
|
274
|
+
# Returns *true* if the type provides a well-defined equality test function
|
275
|
+
def comparable?; false end
|
255
276
|
|
256
|
-
|
277
|
+
# Returns *true* if the type provides a well-defined 'less than' test function
|
278
|
+
def orderable?; false end
|
257
279
|
|
258
|
-
|
280
|
+
# Returns *true* if the type provides a well-defined hash calculation function
|
281
|
+
def hashable?; false end
|
259
282
|
|
260
283
|
# Create forwarding readers which take arbitrary number of arguments
|
261
284
|
[:ctor, :dtor, :copy, :equal, :identify, :less].each do |name|
|
@@ -266,12 +289,6 @@ class Type < Code
|
|
266
289
|
$
|
267
290
|
end
|
268
291
|
|
269
|
-
private
|
270
|
-
|
271
|
-
def define_function(name, signature)
|
272
|
-
Function.new(method_missing(name), signature)
|
273
|
-
end
|
274
|
-
|
275
292
|
end # Type
|
276
293
|
|
277
294
|
|
@@ -299,7 +316,7 @@ class UserDefinedType < Type
|
|
299
316
|
def prefix; @prefix.nil? ? super : @prefix end
|
300
317
|
|
301
318
|
def initialize(opt)
|
302
|
-
opt = {:type => opt} if opt.is_a?(Symbol) || opt.is_a?(String)
|
319
|
+
opt = {:type => opt} if opt.is_a?(::Symbol) || opt.is_a?(::String)
|
303
320
|
if opt.is_a?(Hash)
|
304
321
|
t = opt[:type].nil? ? raise("type is not specified") : opt[:type].to_s
|
305
322
|
else
|
@@ -308,33 +325,55 @@ class UserDefinedType < Type
|
|
308
325
|
super(t)
|
309
326
|
@prefix = AutoC.c_id(opt[:prefix]) unless opt[:prefix].nil?
|
310
327
|
@deps = []; @deps << PublicDeclaration.new(opt[:forward]) unless opt[:forward].nil?
|
311
|
-
opt
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
opt[:identify].nil? ? @capability.subtract([:hashable]) : define_callable(:identify, opt) {def call(obj) "((size_t)(#{obj}))" end}
|
318
|
-
# Handle specific requirements
|
319
|
-
@capability.subtract([:constructible]) if @ctor.parameters.size > 1 # Constructible type must not have extra parameters besides self
|
328
|
+
define_callable(:ctor, opt) {def call(obj) "((#{obj}) = 0)" end}
|
329
|
+
define_callable(:dtor, opt) {def call(obj) end}
|
330
|
+
define_callable(:copy, opt) {def call(dst, src) "((#{dst}) = (#{src}))" end}
|
331
|
+
define_callable(:equal, opt) {def call(lt, rt) "((#{lt}) == (#{rt}))" end}
|
332
|
+
define_callable(:less, opt) {def call(lt, rt) "((#{lt}) < (#{rt}))" end}
|
333
|
+
define_callable(:identify, opt) {def call(obj) "((size_t)(#{obj}))" end}
|
320
334
|
end
|
321
335
|
|
336
|
+
def constructible?; !@ctor.nil? && @ctor.parameters.size == 1 end
|
337
|
+
|
338
|
+
def initializable?; !@ctor.nil? end
|
339
|
+
|
340
|
+
def destructible?; !@dtor.nil? end
|
341
|
+
|
342
|
+
def copyable?; !@copy.nil? end
|
343
|
+
|
344
|
+
def comparable?; !@equal.nil? end
|
345
|
+
|
346
|
+
def orderable?; !@less.nil? end
|
347
|
+
|
348
|
+
def hashable?; !@identify.nil? end
|
349
|
+
|
350
|
+
# The methods below are left empty as the user-defined types have no implementation on their own
|
351
|
+
|
352
|
+
def write_intf_types(stream) end
|
353
|
+
|
354
|
+
def write_intf_decls(stream, declare, define) end
|
355
|
+
|
356
|
+
def write_impls(stream, define) end
|
357
|
+
|
322
358
|
private
|
323
359
|
|
324
360
|
# Default methods creator
|
325
361
|
def define_callable(name, opt, &code)
|
326
|
-
|
327
|
-
|
328
|
-
c = if opt[name] == :unset
|
329
|
-
# Synthesize statement block with default (canonic) parameter list
|
330
|
-
Class.new(Statement, &code).new(instance_variable_get(ivs).parameters)
|
331
|
-
elsif opt[name].is_a?(Function)
|
332
|
-
opt[name] # If a Function instance is given, pass it through
|
362
|
+
c = if opt.has_key?(name) && opt[name].nil?
|
363
|
+
nil # Disable specific capability by explicitly setting the key to nil
|
333
364
|
else
|
334
|
-
|
335
|
-
|
365
|
+
signature = @signature[name]
|
366
|
+
c = if opt[name].nil?
|
367
|
+
# Implicit nil as returned by Hash#default method does synthesize statement block with default (canonic) parameter list
|
368
|
+
Class.new(Statement, &code).new(signature.parameters)
|
369
|
+
elsif opt[name].is_a?(Function)
|
370
|
+
opt[name] # If a Function instance is given, pass it through
|
371
|
+
else
|
372
|
+
# If only a name is specified, assume it is the function name with default signature
|
373
|
+
Function.new(opt[name], signature)
|
374
|
+
end
|
336
375
|
end
|
337
|
-
instance_variable_set(
|
376
|
+
instance_variable_set("@#{name}", c)
|
338
377
|
end
|
339
378
|
|
340
379
|
end # UserDefinedType
|
@@ -376,13 +415,18 @@ class Reference < Type
|
|
376
415
|
def_delegators :@target,
|
377
416
|
:prefix,
|
378
417
|
:public?, :private?, :static?,
|
379
|
-
:constructible?, :
|
380
|
-
|
418
|
+
:constructible?, :initializable?, :destructible?, :comparable?, :orderable?, :hashable?
|
419
|
+
|
420
|
+
# Return *true* since reference copying involves no call to the underlying type's copy constructor
|
421
|
+
def copyable?; true end
|
422
|
+
|
423
|
+
attr_reader :target
|
424
|
+
|
381
425
|
def initialize(target)
|
382
426
|
@target = Type.coerce(target)
|
383
427
|
super(@target.type_ref) # NOTE : the type of the Reference instance itself is actually a pointer type
|
384
|
-
@
|
385
|
-
define_callable(:ctor, @
|
428
|
+
@init = Dispatcher::ParameterArray.new(@target.ctor.parameters[1..-1]) # Capture extra parameters from the target type constructor
|
429
|
+
define_callable(:ctor, @init) {def call(obj, *params) "((#{obj}) = #{@ref.new?}(#{params.join(',')}))" end}
|
386
430
|
define_callable(:dtor, [type]) {def call(obj) "#{@ref.free?}(#{obj})" end}
|
387
431
|
define_callable(:copy, [type, type]) {def call(dst, src) "((#{dst}) = #{@ref.ref?}(#{src}))" end}
|
388
432
|
define_callable(:equal, [type, type]) {def call(lt, rt) @target.equal("*#{lt}", "*#{rt}") end}
|
@@ -401,7 +445,7 @@ class Reference < Type
|
|
401
445
|
/***
|
402
446
|
**** <#{type}> (#{self.class})
|
403
447
|
***/
|
404
|
-
#{declare} #{type} #{new?}(#{@
|
448
|
+
#{declare} #{type} #{new?}(#{@init.declaration});
|
405
449
|
#{declare} #{type} #{ref?}(#{type});
|
406
450
|
#{declare} void #{free?}(#{type});
|
407
451
|
$
|
@@ -410,9 +454,9 @@ class Reference < Type
|
|
410
454
|
def write_impls(stream, define)
|
411
455
|
stream << %$
|
412
456
|
#define AUTOC_COUNTER(p) (*(size_t*)((char*)(p) + sizeof(#{@target.type})))
|
413
|
-
#{define} #{type} #{new?}(#{@
|
457
|
+
#{define} #{type} #{new?}(#{@init.definition}) {
|
414
458
|
#{type} self = (#{type})#{malloc}(sizeof(#{@target.type}) + sizeof(size_t)); #{assert}(self);
|
415
|
-
#{@target.ctor("*self", *@
|
459
|
+
#{@target.ctor("*self", *@init.names)};
|
416
460
|
AUTOC_COUNTER(self) = 1;
|
417
461
|
return self;
|
418
462
|
}
|
@@ -443,15 +487,60 @@ class Reference < Type
|
|
443
487
|
end
|
444
488
|
end # BoundStatement
|
445
489
|
|
446
|
-
def define_callable(name,
|
447
|
-
instance_variable_set("@#{name}", Class.new(BoundStatement, &code).new(self, @target,
|
490
|
+
def define_callable(name, param_types, &code)
|
491
|
+
instance_variable_set("@#{name}", Class.new(BoundStatement, &code).new(self, @target, param_types))
|
448
492
|
end
|
449
493
|
|
450
494
|
end # Reference
|
451
495
|
|
452
496
|
|
497
|
+
# @private
|
498
|
+
module Type::Redirecting
|
499
|
+
|
500
|
+
# Setup special methods which receive types by reference instead of by value
|
501
|
+
def initialize_redirectors
|
502
|
+
define_redirector(:ctor, Function::Signature.new([type_ref^:self]))
|
503
|
+
define_redirector(:dtor, Function::Signature.new([type_ref^:self]))
|
504
|
+
define_redirector(:copy, Function::Signature.new([type_ref^:dst, type_ref^:src]))
|
505
|
+
define_redirector(:equal, Function::Signature.new([type_ref^:lt, type_ref^:rt], :int))
|
506
|
+
define_redirector(:identify, Function::Signature.new([type_ref^:self], :size_t))
|
507
|
+
define_redirector(:less, Function::Signature.new([type_ref^:lt, type_ref^:rt], :int))
|
508
|
+
end
|
509
|
+
|
510
|
+
def write_redirectors(stream, declare, define)
|
511
|
+
# Emit default redirection macros
|
512
|
+
# Unlike other special methods the constructors may have extra arguments
|
513
|
+
# Assume the constructor's first parameter is always a target
|
514
|
+
ctor_ex = ctor.parameters.names[1..-1]
|
515
|
+
ctor_lt = ["self"].concat(ctor_ex).join(',')
|
516
|
+
ctor_rt = ["&self"].concat(ctor_ex).join(',')
|
517
|
+
stream << %$
|
518
|
+
#define _#{ctor}(#{ctor_lt}) #{ctor}(#{ctor_rt})
|
519
|
+
#define _#{dtor}(self) #{dtor}(&self)
|
520
|
+
#define _#{identify}(self) #{identify}(&self)
|
521
|
+
#define _#{copy}(dst,src) #{copy}(&dst,&src)
|
522
|
+
#define _#{equal}(lt,rt) #{equal}(<,&rt)
|
523
|
+
#define _#{less}(lt,rt) #{less}(<,&rt)
|
524
|
+
$
|
525
|
+
end
|
526
|
+
|
527
|
+
private
|
528
|
+
|
529
|
+
# @private
|
530
|
+
class Redirector < Function
|
531
|
+
# Redirect call to the specific macro
|
532
|
+
def call(*params) "_#{name}(" + params.join(',') + ')' end
|
533
|
+
end # Redirector
|
534
|
+
|
535
|
+
def define_redirector(name, signature)
|
536
|
+
instance_variable_set("@#{name}", Redirector.new(method_missing(name), signature))
|
537
|
+
end
|
538
|
+
|
539
|
+
end # Redirecting
|
540
|
+
|
541
|
+
|
453
542
|
# Class adjustments for the function signature definition DSL
|
454
|
-
[Symbol, String, Type].each do |type|
|
543
|
+
[::Symbol, ::String, Type].each do |type|
|
455
544
|
type.class_eval do
|
456
545
|
def ^(name)
|
457
546
|
[self, name]
|
data/test/test.rb
CHANGED
@@ -1,36 +1,158 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This is the AutoC automatic unit test generator.
|
4
|
+
Usage instruction:
|
5
|
+
|
6
|
+
1. Generate get test's source code (test_auto.c and test_auto.h):
|
7
|
+
> ruby -I . -I ../lib test.rb
|
8
|
+
|
9
|
+
2. Compile the generated code:
|
10
|
+
> cc test_auto.c
|
11
|
+
|
12
|
+
3. Run the tests:
|
13
|
+
> ./a.out
|
14
|
+
|
15
|
+
The code is intended to finish succesfully,
|
16
|
+
the process' exit code is zero when all tests are passed
|
17
|
+
ano non-zero if there were failed tests.
|
18
|
+
|
19
|
+
The compile-time warnings are possible and may be ignored.
|
20
|
+
|
21
|
+
The compiled code should also pass the memory leakage tests
|
22
|
+
(with Valgrind, Dr.Memory etc.)
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
require "autoc"
|
27
|
+
|
28
|
+
Prologue = Class.new(AutoC::Code) do
|
29
|
+
def write_defs(stream)
|
30
|
+
stream << %~
|
31
|
+
#include <stdio.h>
|
32
|
+
struct {
|
33
|
+
int total, processed, failed;
|
34
|
+
} tests;
|
35
|
+
int failure;
|
36
|
+
typedef void (*test_func)(void);
|
37
|
+
void run_test(const char* name, test_func func) {
|
38
|
+
fprintf(stdout, "+ %s\\n", name);
|
39
|
+
fflush(stdout);
|
40
|
+
failure = 0;
|
41
|
+
func();
|
42
|
+
if(failure) tests.failed++;
|
43
|
+
tests.processed++;
|
44
|
+
}
|
45
|
+
void print_condition_failure(const char* message, const char* condition, const char* file, int line) {
|
46
|
+
fprintf(stderr, "*** %s : %s (%s:%d)\\n", condition, message, file, line);
|
47
|
+
fflush(stderr);
|
48
|
+
failure = 1;
|
49
|
+
}
|
50
|
+
void print_equality_failure(const char* message, const char* x, const char* y, const char* file, int line) {
|
51
|
+
fprintf(stderr, "*** %s == %s : %s (%s:%d)\\n", x, y, message, file, line);
|
52
|
+
fflush(stderr);
|
53
|
+
failure = 1;
|
54
|
+
}
|
55
|
+
void print_summary(void) {
|
56
|
+
if(tests.failed)
|
57
|
+
fprintf(stdout, "*** Failed %d of %d tests\\n", tests.failed, tests.processed);
|
58
|
+
else
|
59
|
+
fprintf(stdout, "+++ All %d tests passed successfully\\n", tests.processed);
|
60
|
+
fflush(stdout);
|
61
|
+
}
|
62
|
+
#define TEST_MESSAGE(s) fprintf(stderr, "*** %s\\n", s); fflush(stderr);
|
63
|
+
#define TEST_ASSERT(x) if(x) {} else print_condition_failure("evaluated to FALSE", #x, __FILE__, __LINE__)
|
64
|
+
#define TEST_TRUE(x) if(x) {} else print_condition_failure("expected TRUE but got FALSE", #x, __FILE__, __LINE__)
|
65
|
+
#define TEST_FALSE(x) if(x) print_condition_failure("expected FALSE but got TRUE", #x, __FILE__, __LINE__)
|
66
|
+
#define TEST_NULL(x) if((x) == NULL) {} else print_condition_failure("expected NULL", #x, __FILE__, __LINE__)
|
67
|
+
#define TEST_NOT_NULL(x) if((x) == NULL) print_condition_failure("expected not NULL", #x, __FILE__, __LINE__)
|
68
|
+
#define TEST_EQUAL(x, y) if((x) == (y)) {} else print_equality_failure("expected equality", #x, #y, __FILE__, __LINE__)
|
69
|
+
#define TEST_NOT_EQUAL(x, y) if((x) == (y)) print_equality_failure("expected non-equality", #x, #y, __FILE__, __LINE__)
|
70
|
+
#define TEST_EQUAL_CHARS(x, y) if(strcmp(x, y) == 0) {} else print_equality_failure("expected strings equality", #x, #y, __FILE__, __LINE__)
|
71
|
+
#define TEST_NOT_EQUAL_CHARS(x, y) if(strcmp(x, y) == 0) print_equality_failure("expected strings non-equality", #x, #y, __FILE__, __LINE__)
|
72
|
+
~
|
73
|
+
end
|
74
|
+
end.new
|
75
|
+
|
76
|
+
|
77
|
+
Epilogue = Class.new(AutoC::Code) do
|
78
|
+
def priority; AutoC::Priority::MIN end
|
79
|
+
def write_defs(stream)
|
80
|
+
total = 0
|
81
|
+
$tests.each {|t| total += t.tests.size}
|
82
|
+
stream << %~int main(int argc, char** argv) {~
|
83
|
+
stream << %~
|
84
|
+
tests.total = #{total};
|
85
|
+
tests.processed = tests.failed = 0;
|
86
|
+
~
|
87
|
+
$tests.each {|t| t.write_test_calls(stream)}
|
88
|
+
stream << %~print_summary();~
|
89
|
+
stream << %~return tests.failed > 0;}~
|
90
|
+
end
|
91
|
+
end.new
|
92
|
+
|
93
|
+
|
94
|
+
$tests = []
|
95
|
+
|
96
|
+
|
97
|
+
def type_test(cls, *opts, &code)
|
98
|
+
t = Class.new(cls) do
|
99
|
+
def entities; super << Prologue end
|
100
|
+
attr_reader :tests
|
101
|
+
def initialize(*args)
|
102
|
+
super
|
103
|
+
@tests = []
|
104
|
+
@test_names = []
|
105
|
+
end
|
106
|
+
def setup(code = nil)
|
107
|
+
@setup_code = code
|
108
|
+
end
|
109
|
+
def cleanup(code = nil)
|
110
|
+
@cleanup_code = code
|
111
|
+
end
|
112
|
+
def test(name, code)
|
113
|
+
s = name.to_s
|
114
|
+
@test_names << [name, func_name = eval("test#{s[0,1].upcase}#{s[1..-1]}")]
|
115
|
+
@tests << %~
|
116
|
+
void #{func_name}(void) {
|
117
|
+
#{@setup_code}
|
118
|
+
#{code}
|
119
|
+
#{@cleanup_code}
|
120
|
+
}
|
121
|
+
~
|
122
|
+
end
|
123
|
+
def write_defs(stream)
|
124
|
+
super
|
125
|
+
@tests.each {|f| stream << f}
|
126
|
+
stream << %~void #{runTests}(void) {~
|
127
|
+
stream << %~
|
128
|
+
fprintf(stdout, "+ %s\\n", "#{type}");
|
129
|
+
fflush(stdout);
|
130
|
+
~
|
131
|
+
@test_names.each do |name, func_name|
|
132
|
+
stream << %~
|
133
|
+
run_test("#{name}", #{func_name});
|
134
|
+
~
|
135
|
+
end
|
136
|
+
stream << %~
|
137
|
+
fputs("\\n", stdout); fflush(stdout);}
|
138
|
+
~
|
139
|
+
end
|
140
|
+
def write_test_calls(stream)
|
141
|
+
stream << %$
|
142
|
+
#{runTests}();
|
143
|
+
$
|
144
|
+
end
|
145
|
+
end.new(*opts)
|
146
|
+
$tests << t
|
147
|
+
t.instance_eval(&code)
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
Dir["**/test_*.rb"].each {|t| load t}
|
152
|
+
|
153
|
+
|
154
|
+
AutoC::Module.generate!(:Test) do |c|
|
155
|
+
c << Prologue
|
156
|
+
$tests.each {|t| c << t}
|
157
|
+
c << Epilogue
|
36
158
|
end
|