autoc 1.2 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
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