Class: TTK::Strategies::Strategy

Inherits:
Object
  • Object
show all
Includes:
Abstract, AttributedClass
Defined in:
lib/ttk/strategies/Strategy.rb,
lib/ttk/strategies/Strategy/assert_eval.rb

Overview

This is the base class for anything testable. It provides some basics attributes like the name of the test.

Defined Under Namespace

Classes: AssertEval, Failure

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Strategy

Create a new Strategy with the given optional document.



62
63
64
65
66
67
68
69
# File 'lib/ttk/strategies/Strategy.rb', line 62

def initialize ( &block )
  @status = StartStatus.new
  @symbols = {}
  initialize_attributes
  @save = nil
	@reject = Set.new
  block[self] if block_given?
end

Instance Attribute Details

#statusObject (readonly)

Accessors



54
55
56
# File 'lib/ttk/strategies/Strategy.rb', line 54

def status
  @status
end

#symtblObject

Accessors



54
55
56
# File 'lib/ttk/strategies/Strategy.rb', line 54

def symtbl
  @symtbl
end

Instance Method Details

#abort(message = 'abort explicitly') ⇒ Object

Abort the test explicitly.



524
525
526
527
# File 'lib/ttk/strategies/Strategy.rb', line 524

def abort ( message='abort explicitly' )
  @symtbl[:flow] << :abort # FIXME
  raise_status AbortStatus.new(@symtbl[:flow], message)
end

#assign(hsh) ⇒ Object

Assign a hsh keeping at last the attribute referenced by assign_at_last.



256
257
258
259
260
# File 'lib/ttk/strategies/Strategy.rb', line 256

def assign(hsh)
	last = assign_at_last
	hsh.each_pair { |key, val| assign_one(key, val) if key.to_sym != last }
	assign_one(last, hsh[last]) if hsh.has_key? last
end

#clean_instance_variablesObject



347
348
349
350
351
352
353
354
# File 'lib/ttk/strategies/Strategy.rb', line 347

def clean_instance_variables
  attrs = Set.new(self.class.attributes.map { |a| "@#{a.name}" })
  vars = Set.new(instance_variables)
  exceptions = Set.new(%w[ @status @thread @symtbl ])
  (vars - attrs - exceptions).each do |var|
    remove_instance_variable var
  end
end

#display_unexpected_exc(exc) ⇒ Object



554
555
556
# File 'lib/ttk/strategies/Strategy.rb', line 554

def display_unexpected_exc ( exc )
  @log.error_unexpected_exception = exc.long_pp
end

#display_unexpected_synflow_exc(exc, arg) ⇒ Object



558
559
560
# File 'lib/ttk/strategies/Strategy.rb', line 558

def display_unexpected_synflow_exc ( exc, arg )
  @log.error_unexpected_synflow_exception = arg
end

#fail(*args) ⇒ Object

Force the test to fail



519
520
521
# File 'lib/ttk/strategies/Strategy.rb', line 519

def fail ( *args )
  raise_status_custom FailStatus, *args
end

#initialize_flow_factoryObject



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/ttk/strategies/Strategy.rb', line 270

def initialize_flow_factory
  factory = SynFlowFactory.new
  factory <<
    {
      :start_st           => {
                               :prologue       => :prologue_st,
                               :not_running?   => :start_st,
                               :end_run_impl   => :after_run_st,
                               # :abort          => :start_st,
                               :error          => :error_st
                             },

      :prologue_st        => {
                               :begin_run_impl => :run_impl_st,
                               :error          => :error_st
                             },

      :run_impl_st        => {
                               :prologue       => :prologue_st,
                               :end_run_impl   => :after_run_st,
                               :abort          => :abort_st,
                               :error          => :error_st
                             },

      :after_run_st       => {
                               :epilogue       => :epilogue_st,
                               :error          => :error_st
                             },

      :epilogue_st        => {
                               :finish         => :start_st,
                               :error          => :error_st
                             },

      :abort_st           => {
                               :end_run_impl   => :after_run_abort_st,
                               :abort          => :abort_st,
                               :error          => :error_st
                             },

      :after_run_abort_st => {
                               :epilogue       => :epilogue_abort_st,
                               :abort          => :after_run_abort_st,
                               :error          => :error_st
                             },

      :epilogue_abort_st  => {
                               :finish         => :start_st,
                               :error          => :error_st
                             },

      :error_st           => {
                               :prologue       => :prologue_st,
                               :begin_run_impl => :run_impl_st,
                               :end_run_impl   => :after_run_st,
                               :epilogue       => :epilogue_st,
                               :finish         => :start_st,
                               :no_running?    => :error_st,
                               :error          => :error_st,
                               :abort          => :abort_st
                             },
    }
  factory.initial = :start_st
  @symtbl[:flow_factory] = factory
  @symtbl[:flow] = factory.new_flow
end

#passObject

Force the test to pass



503
504
505
# File 'lib/ttk/strategies/Strategy.rb', line 503

def pass
  raise_status PassStatus.new
end

#raise_error(message = nil) ⇒ Object

Force an Error status



513
514
515
516
# File 'lib/ttk/strategies/Strategy.rb', line 513

def raise_error ( message=nil )
  @symtbl[:flow] << :error
  raise_status ErrorStatus.new(message)
end

#reject(*att) ⇒ Object

Reject



266
267
268
# File 'lib/ttk/strategies/Strategy.rb', line 266

def reject ( *att )
	@reject += att.map! { |a| a.to_sym }
end

#run(log = @symtbl[:log]) ⇒ Object Also known as: call

Runs this test, proceding like this:

- pre_assertion
- prologue
- run_impl
- assertion
- post_assertion
- epilogue


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/ttk/strategies/Strategy.rb', line 82

def run ( log=@symtbl[:log] )
  @log = log
  initialize_flow_factory if @symtbl[:flow_factory].nil?
  flow = @symtbl[:flow]
  flow << :prologue

  @status = RunningStatus.new
  @thread = Thread.current

  aborted = nil

  saved_path_size = @log.path_size
  begin
    begin

      # Pre assertion
      pre_assertion_failed = nil
      begin
        unless r = pre_assertion()
          pre_assertion_failed = "Pre assertion failed (#{r.inspect})"
        end
      rescue Exception => ex
        pre_assertion_failed = ex
      end
      if pre_assertion_failed
        @log.new_node(to_s)
        @symtbl[:flow] << :error
        skip(pre_assertion_failed)
      end

      begin
        prologue()
        # @log.flow_id = flow.i

      # Catch all other exceptions and wrapped them in an error.
      rescue Exception => ex
        raise_error(ex)
      end

      msg = "abort `%name' with timeout #{@timeout}s"
      specific_abort = TimeoutAbortStatus.new(flow, msg)

      begin
        flow << :begin_run_impl
        skip_if_cached
        Timeout.timeout(@timeout, specific_abort) do
          run_impl()
        end
      ensure
        flow << :end_run_impl
      end

      # Post assertion
      post_assertion_failed = nil
      begin
        unless r = post_assertion()
          post_assertion_failed = "Post assertion failed (#{r.inspect})"
        end
      rescue Exception => ex
        post_assertion_failed = ex
      end
      fail(post_assertion_failed) if post_assertion_failed


      # Assertion
      assertion()


      raise_error('no status given')

    # Forward StatusException
    rescue StatusException => ex
      st = ex.status
      # Put the exception in `aborted' if it dosen't concern me and abort.
      if st.is_a? TimeoutAbortStatus
        aborted = ex if st != specific_abort
        st.message.gsub!('%name', @name.to_s)
      end
      raise ex

    # Convert the Failure exception with `fail' (Warn: almost deprecated).
    rescue Failure => ex
      fail(ex)

    # Catch all others exceptions and wrapped them in an error.
    rescue Exception => ex
      raise_error(ex)
    end

  # Threat Status exceptions
  rescue StatusException => ex
    begin

      flow << :epilogue
      @status = ex.status
      # Call the specific hook (pass_hook, failed_hook...).
      send(ex.status.hook_name)
      epilogue() unless pre_assertion_failed

    rescue SynFlow::Error => ex
      display_unexpected_synflow_exc ex, :epilogue

    rescue Exception => ex
      display_unexpected_exc ex
    end

  rescue Exception => ex
    display_unexpected_exc ex
  end

  begin
    @status.to_ttk_log(@log) unless @reject.include?(:status)
    @status.weight *= @weight
    (@log.path_size - saved_path_size).times { |i| @log.up }
    if cache = @symtbl[:cache]
      cache[@symtbl[:pathname]] =
      {
        :status => @status,
        :symtbl => @symtbl.local
      }
    end
    @reject.clear if defined? @reject
    clean_instance_variables
    flow << :finish
  rescue SynFlow::Error => ex
    display_unexpected_synflow_exc ex, :finish
  rescue Exception => ex
    display_unexpected_exc ex
  end
  raise aborted unless aborted.nil?
	return @status

end

#running?Boolean

Returns:

  • (Boolean)


550
551
552
# File 'lib/ttk/strategies/Strategy.rb', line 550

def running?
  defined? @status and @status.is_a? RunningStatus
end

#skip(*args) ⇒ Object

Skip the test



508
509
510
# File 'lib/ttk/strategies/Strategy.rb', line 508

def skip ( *args )
  raise_status_custom SkipStatus, *args
end

#skip_if_cachedObject



337
338
339
340
341
342
343
344
345
# File 'lib/ttk/strategies/Strategy.rb', line 337

def skip_if_cached
  if cache = @symtbl[:use_cache]
    me = cache[@symtbl[:pathname]]
    if me and @symtbl[:cache_proc][self, me[:status]]
      @symtbl.local.merge!(me[:symtbl])
      skip(@wclass.new(me[:status].weight))
    end
  end
end

#strategyObject



569
570
571
# File 'lib/ttk/strategies/Strategy.rb', line 569

def strategy
  self.class
end

#strategy=(aClass) ⇒ Object



573
574
575
576
577
578
# File 'lib/ttk/strategies/Strategy.rb', line 573

def strategy= ( aClass )
  if aClass != Strategy and aClass != self.class
    raise ArgumentError, "Cannot change the strategy class " +
                         "of a test (#{aClass} != #{self.class})"
  end
end

#symbols=(symbols) ⇒ Object

FIXME: I’m not well dumped



563
564
565
566
567
# File 'lib/ttk/strategies/Strategy.rb', line 563

def symbols= ( symbols )
  symbols.each do |k, v|
    @symbols[k] = v
  end
end

#testify(opts = nil) ⇒ Object

Build methods



534
535
536
# File 'lib/ttk/strategies/Strategy.rb', line 534

def testify ( opts=nil )
  self
end

#timeout=(other) ⇒ Object



542
543
544
545
546
547
548
# File 'lib/ttk/strategies/Strategy.rb', line 542

def timeout=(other)
  if other >= 0
    @timeout = other
  else
    raise(ArgumentError, "`#{other}' - timeout delay must be >= 0")
  end
end

#to_sObject



538
539
540
# File 'lib/ttk/strategies/Strategy.rb', line 538

def to_s
  @name || @log.path.to_s || super
end

#wclass=(other) ⇒ Object

Custom accessors



222
223
224
225
226
227
228
# File 'lib/ttk/strategies/Strategy.rb', line 222

def wclass=(other)
	if other.is_a?(Class)
	  @wclass = other
	else
	  @wclass = TTK::Weights.const_get(other.to_s)
	end
end