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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/README +3 -1
  4. data/doc/AutoC.html +23 -7
  5. data/doc/AutoC/Code.html +3 -3
  6. data/doc/AutoC/Collection.html +289 -76
  7. data/doc/AutoC/HashMap.html +44 -46
  8. data/doc/AutoC/HashSet.html +20 -17
  9. data/doc/AutoC/List.html +56 -92
  10. data/doc/AutoC/Module.html +2 -2
  11. data/doc/AutoC/Module/File.html +2 -2
  12. data/doc/AutoC/Module/Header.html +6 -4
  13. data/doc/AutoC/Module/Source.html +26 -26
  14. data/doc/AutoC/Priority.html +2 -2
  15. data/doc/AutoC/Queue.html +30 -92
  16. data/doc/AutoC/Reference.html +217 -61
  17. data/doc/AutoC/String.html +1393 -0
  18. data/doc/AutoC/Type.html +240 -128
  19. data/doc/AutoC/UserDefinedType.html +688 -47
  20. data/doc/AutoC/Vector.html +154 -62
  21. data/doc/_index.html +9 -2
  22. data/doc/class_list.html +1 -1
  23. data/doc/file.CHANGES.html +10 -2
  24. data/doc/file.README.html +5 -3
  25. data/doc/index.html +5 -3
  26. data/doc/method_list.html +235 -97
  27. data/doc/top-level-namespace.html +2 -2
  28. data/lib/autoc.rb +3 -1
  29. data/lib/autoc/code.rb +3 -2
  30. data/lib/autoc/collection.rb +36 -40
  31. data/lib/autoc/collection/hash_map.rb +10 -14
  32. data/lib/autoc/collection/hash_set.rb +12 -11
  33. data/lib/autoc/collection/list.rb +21 -11
  34. data/lib/autoc/collection/queue.rb +5 -8
  35. data/lib/autoc/collection/vector.rb +28 -12
  36. data/lib/autoc/string.rb +492 -0
  37. data/lib/autoc/type.rb +155 -66
  38. data/test/test.rb +157 -35
  39. data/test/test_char_string.rb +270 -0
  40. data/test/test_int_list.rb +35 -0
  41. data/test/test_int_vector.rb +34 -0
  42. data/test/test_value_hash_map.rb +162 -0
  43. data/test/test_value_hash_set.rb +173 -0
  44. data/test/test_value_list.rb +193 -0
  45. data/test/test_value_queue.rb +275 -0
  46. data/test/test_value_vector.rb +155 -0
  47. data/test/value.rb +80 -0
  48. metadata +15 -8
  49. data/test/test.c +0 -1041
  50. data/test/test.h +0 -41
  51. data/test/test_auto.c +0 -3407
  52. data/test/test_auto.h +0 -765
@@ -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(',') end
28
- def declaration; types.join(',') end
29
- def definition; collect {|x| "#{x.first} #{x.last}"}.join(',') end
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
- #ifdef _MSC_VER
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 AUTOC_STATIC
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
- #ifdef _MSC_VER
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
- @ctor_signature = Function::Signature.new([type^:self])
175
- @dtor_signature = Function::Signature.new([type^:self])
176
- @copy_signature = Function::Signature.new([type^:dst, type^:src])
177
- @equal_signature = Function::Signature.new([type^:lt, type^:rt], :int)
178
- @identify_signature = Function::Signature.new([type^:self], :size_t)
179
- @less_signature = Function::Signature.new([type^:lt, type^:rt], :int)
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; "AUTOC_EXTERN" end
237
+ def extern; :AUTOC_EXTERN end
227
238
 
228
- def inline; "AUTOC_INLINE" end
239
+ def inline; :AUTOC_INLINE end
229
240
 
230
- def static; "AUTOC_STATIC" end
241
+ def static; :AUTOC_STATIC end
231
242
 
232
- def assert; "assert" end
243
+ def assert; :assert end
233
244
 
234
- def malloc; "malloc" end
245
+ def malloc; :malloc end
235
246
 
236
- def calloc; "calloc" end
247
+ def calloc; :calloc end
237
248
 
238
- def free; "free" end
249
+ def free; :free end
239
250
 
240
- def abort; "abort" end
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
- def constructible?; @capability.include?(:constructible) end
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
- def destructible?; @capability.include?(:destructible) end
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
- def copyable?; @capability.include?(:copyable) end
268
+ # Returns *true* if the type provides a well-defined type destructor
269
+ def destructible?; false end
253
270
 
254
- def comparable?; @capability.include?(:comparable) end
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
- def orderable?; @capability.include?(:orderable) && comparable? end
277
+ # Returns *true* if the type provides a well-defined 'less than' test function
278
+ def orderable?; false end
257
279
 
258
- def hashable?; @capability.include?(:hashable) && comparable? end
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.default = :unset # This allows to use nil as a value to indicate that the specific method is not avaliable
312
- opt[:ctor].nil? ? @capability.subtract([:constructible]) : define_callable(:ctor, opt) {def call(obj) "((#{obj}) = 0)" end}
313
- opt[:dtor].nil? ? @capability.subtract([:destructible]) : define_callable(:dtor, opt) {def call(obj) end}
314
- opt[:copy].nil? ? @capability.subtract([:copyable]) : define_callable(:copy, opt) {def call(dst, src) "((#{dst}) = (#{src}))" end}
315
- opt[:equal].nil? ? @capability.subtract([:comparable]) : define_callable(:equal, opt) {def call(lt, rt) "((#{lt}) == (#{rt}))" end}
316
- opt[:less].nil? ? @capability.subtract([:orderable]) : define_callable(:less, opt) {def call(lt, rt) "((#{lt}) < (#{rt}))" end}
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
- iv = "@#{name}"
327
- ivs = "@#{name}_signature"
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
- # If only a name is specified, assume it is the function name with default signature
335
- Function.new(opt[name], instance_variable_get(ivs))
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(iv, c)
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?, :destructible?, :copyable?, :comparable?, :orderable?, :hashable?
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
- @ctor_params = Dispatcher::ParameterArray.new(@target.ctor.parameters[1..-1]) # Capture extra parameters from the target type constructor
385
- define_callable(:ctor, @ctor_params) {def call(obj, *params) "((#{obj}) = #{@ref.new?}(#{params.join(',')}))" end}
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?}(#{@ctor_params.declaration});
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?}(#{@ctor_params.definition}) {
457
+ #{define} #{type} #{new?}(#{@init.definition}) {
414
458
  #{type} self = (#{type})#{malloc}(sizeof(#{@target.type}) + sizeof(size_t)); #{assert}(self);
415
- #{@target.ctor("*self", *@ctor_params.names)};
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, params, &code)
447
- instance_variable_set("@#{name}", Class.new(BoundStatement, &code).new(self, @target, params))
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}(&lt,&rt)
523
+ #define _#{less}(lt,rt) #{less}(&lt,&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]
@@ -1,36 +1,158 @@
1
- require "autoc"
2
-
3
- ValueType = {
4
- :type => :ValueType,
5
- :ctor => :ValueTypeCtor,
6
- :dtor => :ValueTypeDtor,
7
- :copy => :ValueTypeCopy,
8
- :equal => :ValueTypeEqual,
9
- :less => :ValueTypeLess,
10
- :identify => :ValueTypeIdentify,
11
- :forward => %$#include "test.h"$,
12
- }
13
-
14
- PInt = AutoC::Reference.new(:type => "int", :prefix => "Int")
15
-
16
- PValueType = AutoC::Reference.new(ValueType)
17
-
18
- IntVector = AutoC::Vector.new(:IntVector, :int)
19
-
20
- IntSet = AutoC::HashSet.new(:IntSet, :int)
21
-
22
- ListIntSet = AutoC::List.new(:ListIntSet, IntSet)
23
-
24
- AutoC::Module.generate!(:Test) do |c|
25
- c << AutoC::Vector.new(:ValueTypeVector, ValueType)
26
- c << AutoC::List.new(:ValueTypeList, ValueType)
27
- c << AutoC::Queue.new(:ValueTypeQueue, ValueType)
28
- c << AutoC::HashSet.new(:ValueTypeSet, ValueType)
29
- c << AutoC::HashMap.new(:ValueTypeMap, ValueType, ValueType)
30
- c << AutoC::HashMap.new(:IntStrMap, "int", "const char *")
31
- c << ListIntSet
32
- c << IntSet
33
- c << AutoC::Vector.new(:PIntVector, PInt)
34
- c << PInt << PValueType
35
- c << AutoC::List.new(:ListPVectorValue, AutoC::Reference.new(AutoC::Vector.new(:PVectorValue, PValueType)))
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