diff --git a/lib/Accessor.rb b/lib/Accessor.rb index 8e37b5f..b2935c5 100644 --- a/lib/Accessor.rb +++ b/lib/Accessor.rb @@ -18,6 +18,7 @@ class Accessor attr_accessor :renderer attr_accessor :path attr_accessor :output_path + attr_accessor :control_failed def initialize() @@ -29,6 +30,7 @@ def initialize() @renderer = nil @path = nil @output_path = nil + @control_failed = false end diff --git a/lib/Aggregator.rb b/lib/Aggregator.rb index 6c1bd23..8e4d548 100644 --- a/lib/Aggregator.rb +++ b/lib/Aggregator.rb @@ -21,6 +21,7 @@ def initialize(meta_map) @meta_map = meta_map # Key rule sets by class and method. + # TODO: Possible bug "@rule_sets={nil=>{nil=>{:output=># message - @status = :fail - @message = message - # When pass. - else - @status = :pass - end - - end - ## # Get the results of the control reflection. # @@ -63,11 +35,14 @@ def result() :method => @method, :status => @status, :message => @message, - :inputs => [], + :inputs => nil, :output => @output, } - @inputs.each do |meta| - control[:inputs] << meta.result() + unless @inputs.nil? + control[:inputs] = [] + @inputs.each do |meta| + control[:inputs] << meta.result() + end end return control diff --git a/lib/Execution.rb b/lib/Execution.rb index d16628a..f08cfae 100644 --- a/lib/Execution.rb +++ b/lib/Execution.rb @@ -28,10 +28,10 @@ class Execution # # @param object [Object] The calling object. # @param method [Symbol] The calling method. - # @param number [Integer] The number of reflections to create per execution. + # @param reflect_amount [Integer] The number of reflections to create per execution. # @param stack [ShadowStack] The shadow execution call stack. ## - def initialize(caller_object, method, number, stack) + def initialize(caller_object, method, reflect_amount, stack) @time = Time.now.to_i @unique_id = @time + rand(1..99999) @@ -51,7 +51,7 @@ def initialize(caller_object, method, number, stack) # Reflections. @control = nil - @reflections = Array.new(number) + @reflections = Array.new(reflect_amount) # State. if @stack.peek() == nil diff --git a/lib/Reflection.rb b/lib/Reflection.rb index 4443db7..8eba3ea 100644 --- a/lib/Reflection.rb +++ b/lib/Reflection.rb @@ -15,6 +15,8 @@ class Reflection + attr_reader :status + ## # Create a Reflection. # @@ -36,49 +38,56 @@ def initialize(execution, number, aggregator) @method = execution.method # Metadata. - @inputs = [] + @inputs = nil @output = nil # Clone the execution's calling object. - @clone = Clone.new(execution) - @clone_id = nil + # TODO: Abstract away into Clone class. + @clone = execution.caller_object.clone # Result. @status = :pass @time = Time.now.to_i + @message = nil end ## # Reflect on a method. # - # Creates a shadow execution stack. + # Creates a shadow execution. # @param *args [Dynamic] The method's arguments. ## def reflect(*args) - # Get aggregated RuleSets. - agg_input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method) - agg_output_rule_set = @aggregator.get_output_rule_set(@klass, @method) + # Get arguments. + new_args = [] + unless args.size == 0 + + # Get aggregated RuleSets. + agg_input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method) + agg_output_rule_set = @aggregator.get_output_rule_set(@klass, @method) - # Create random arguments. - new_args = randomize(args) + # Create random arguments. + new_args = randomize(args) - # Create metadata for each argument. - @inputs = MetaBuilder.create_many(new_args) + # Create metadata for each argument. + @inputs = MetaBuilder.create_many(new_args) + + end # Action method with new arguments. begin - # Validate input with aggregated control RuleSets. - unless agg_input_rule_sets.nil? + # Validate inputs against aggregated control RuleSets. + unless args.size == 0 || agg_input_rule_sets.nil? unless @aggregator.validate_inputs(new_args, agg_input_rule_sets) @status = :fail end end # Run reflection. - output = @clone.call(@method, *new_args) + output = @clone.send(@method, *new_args) @output = MetaBuilder.create(output) # Validate output with aggregated control RuleSets. @@ -143,11 +152,14 @@ def result() :method => @method, :status => @status, :message => @message, - :inputs => [], + :inputs => nil, :output => @output, } - @inputs.each do |meta| - reflection[:inputs] << meta.result() + unless @inputs.nil? + reflection[:inputs] = [] + @inputs.each do |meta| + reflection[:inputs] << meta.result() + end end return reflection diff --git a/lib/Reflekt.rb b/lib/Reflekt.rb index b5d6631..bfded1c 100644 --- a/lib/Reflekt.rb +++ b/lib/Reflekt.rb @@ -34,6 +34,7 @@ module Reflekt def initialize(*args) + # TODO: Store counts on @@reflekt and key by instance ID. @reflekt_counts = {} # Get child and parent instance methods. @@ -49,74 +50,88 @@ def initialize(*args) # When method called in flow. self.define_singleton_method(method) do |*args| - # Get current execution. - execution = @@reflekt.stack.peek() + # Don't reflect further if the control reflection fails. + unless @@reflekt.control_failed - # Don't reflect when reflect limit reached or method skipped. - unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method) + # Get current execution. + execution = @@reflekt.stack.peek() - # When stack empty or past execution done reflecting. - if execution.nil? || execution.has_finished_reflecting? + # Don't reflect when reflect limit reached or method skipped. + unless (@reflekt_counts[method] >= @@reflekt.config.reflect_limit) || self.class.reflekt_skipped?(method) - # Create execution. - execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack) + # When stack empty or past execution done reflecting. + if execution.nil? || execution.has_finished_reflecting? - @@reflekt.stack.push(execution) + # Create execution. + execution = Execution.new(self, method, @@reflekt.config.reflect_amount, @@reflekt.stack) - end + @@reflekt.stack.push(execution) - ## - # Reflect the execution. - # - # The first method call in the Execution creates a Reflection. - # Subsequent method calls are shadow executions on cloned objects. - ## - if execution.has_empty_reflections? && !execution.is_reflecting? - execution.is_reflecting = true + end - # Create control. - control = Control.new(execution, 1, @@reflekt.aggregator) - execution.control = control + ## + # Reflect the execution. + # + # The first method call in the Execution creates a Reflection. + # Subsequent method calls are shadow executions on cloned objects. + ## + if execution.has_empty_reflections? && !execution.is_reflecting? + execution.is_reflecting = true - # Execute control. - control.reflect(*args) + # Create control. + control = Control.new(execution, 0, @@reflekt.aggregator) + execution.control = control - # Save control. - @@reflekt.db.get("controls").push(control.result()) + # Execute control. + control.reflect(*args) + if control.status == :fail + @@reflekt.control_failed = true + else - # Multiple reflections per execution. - execution.reflections.each_with_index do |value, index| + # Multiple reflections per execution. + execution.reflections.each_with_index do |value, index| - # Create reflection. - reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator) - execution.reflections[index] = reflection + # Create reflection. + reflection = Reflection.new(execution, index + 1, @@reflekt.aggregator) + execution.reflections[index] = reflection - # Execute reflection. - reflection.reflect(*args) - @reflekt_counts[method] = @reflekt_counts[method] + 1 + # Execute reflection. + reflection.reflect(*args) + @reflekt_counts[method] = @reflekt_counts[method] + 1 - # Save reflection. - @@reflekt.db.get("reflections").push(reflection.result()) + # Save reflection. + @@reflekt.db.get("reflections").push(reflection.result()) - end + end + + # Save control. + @@reflekt.db.get("controls").push(control.result()) + + # Save results. + @@reflekt.db.write() - # Save results. - @@reflekt.db.write() + # Render results. + @@reflekt.renderer.render() + + end - # Render results. - @@reflekt.renderer.render() + execution.is_reflecting = false + end - execution.is_reflecting = false end - end + # Don't execute skipped methods when reflecting. + unless execution.is_reflecting? && self.class.reflekt_skipped?(method) - # Don't execute skipped methods when reflecting. - unless execution.is_reflecting? && self.class.reflekt_skipped?(method) + # Continue execution / shadow execution. + super *args - # Continue execution / shadow execution. - super *args + end + # Continue execution when control fails. + else + # Execute error producing code. + super *args end end diff --git a/lib/web/bundle.js b/lib/web/bundle.js index 813145b..8ab5fcf 100644 --- a/lib/web/bundle.js +++ b/lib/web/bundle.js @@ -1,9 +1,9 @@ -!function(e){var t=window.webpackHotUpdate;window.webpackHotUpdate=function(e,n){!function(e,t){if(!x[e]||!w[e])return;for(var n in w[e]=!1,t)Object.prototype.hasOwnProperty.call(t,n)&&(m[n]=t[n]);0==--v&&0===b&&T()}(e,n),t&&t(e,n)};var n,r=!0,o="b92c1efb0d17d6c3dca3",i={},a=[],l=[];function u(e){var t=O[e];if(!t)return N;var r=function(r){return t.hot.active?(O[r]?-1===O[r].parents.indexOf(e)&&O[r].parents.push(e):(a=[e],n=r),-1===t.children.indexOf(r)&&t.children.push(r)):(console.warn("[HMR] unexpected require("+r+") from disposed module "+e),a=[]),N(r)},o=function(e){return{configurable:!0,enumerable:!0,get:function(){return N[e]},set:function(t){N[e]=t}}};for(var i in N)Object.prototype.hasOwnProperty.call(N,i)&&"e"!==i&&"t"!==i&&Object.defineProperty(r,i,o(i));return r.e=function(e){return"ready"===f&&d("prepare"),b++,N.e(e).then(t,(function(e){throw t(),e}));function t(){b--,"prepare"===f&&(g[e]||S(e),0===b&&0===v&&T())}},r.t=function(e,t){return 1&t&&(e=r(e)),N.t(e,-2&t)},r}function c(t){var r={_acceptedDependencies:{},_declinedDependencies:{},_selfAccepted:!1,_selfDeclined:!1,_selfInvalidated:!1,_disposeHandlers:[],_main:n!==t,active:!0,accept:function(e,t){if(void 0===e)r._selfAccepted=!0;else if("function"==typeof e)r._selfAccepted=e;else if("object"==typeof e)for(var n=0;n=0&&r._disposeHandlers.splice(t,1)},invalidate:function(){switch(this._selfInvalidated=!0,f){case"idle":(m={})[t]=e[t],d("ready");break;case"ready":C(t);break;case"prepare":case"check":case"dispose":case"apply":(y=y||[]).push(t)}},check:E,apply:_,status:function(e){if(!e)return f;s.push(e)},addStatusHandler:function(e){s.push(e)},removeStatusHandler:function(e){var t=s.indexOf(e);t>=0&&s.splice(t,1)},data:i[t]};return n=void 0,r}var s=[],f="idle";function d(e){f=e;for(var t=0;t0;){var o=r.pop(),i=o.id,a=o.chain;if((s=O[i])&&(!s.hot._selfAccepted||s.hot._selfInvalidated)){if(s.hot._selfDeclined)return{type:"self-declined",chain:a,moduleId:i};if(s.hot._main)return{type:"unaccepted",chain:a,moduleId:i};for(var l=0;l ")),T.type){case"self-declined":r.onDeclined&&r.onDeclined(T),r.ignoreDeclined||(_=new Error("Aborted because of self decline: "+T.moduleId+R));break;case"declined":r.onDeclined&&r.onDeclined(T),r.ignoreDeclined||(_=new Error("Aborted because of declined dependency: "+T.moduleId+" in "+T.parentId+R));break;case"unaccepted":r.onUnaccepted&&r.onUnaccepted(T),r.ignoreUnaccepted||(_=new Error("Aborted because "+f+" is not accepted"+R));break;case"accepted":r.onAccepted&&r.onAccepted(T),C=!0;break;case"disposed":r.onDisposed&&r.onDisposed(T),j=!0;break;default:throw new Error("Unexception type "+T.type)}if(_)return d("abort"),Promise.reject(_);if(C)for(f in w[f]=m[f],v(g,T.outdatedModules),T.outdatedDependencies)Object.prototype.hasOwnProperty.call(T.outdatedDependencies,f)&&(b[f]||(b[f]=[]),v(b[f],T.outdatedDependencies[f]));j&&(v(g,[T.moduleId]),w[f]=E)}var D,z=[];for(u=0;u0;)if(f=F.pop(),s=O[f]){var A={},L=s.hot._disposeHandlers;for(c=0;c=0&&U.parents.splice(D,1))}}for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)&&(s=O[f]))for(M=b[f],c=0;c=0&&s.children.splice(D,1);d("apply"),void 0!==h&&(o=h,h=void 0);for(f in m=void 0,w)Object.prototype.hasOwnProperty.call(w,f)&&(e[f]=w[f]);var H=null;for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)&&(s=O[f])){M=b[f];var V=[];for(u=0;ue.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0&&r._disposeHandlers.splice(t,1)},invalidate:function(){switch(this._selfInvalidated=!0,f){case"idle":(m={})[t]=e[t],d("ready");break;case"ready":C(t);break;case"prepare":case"check":case"dispose":case"apply":(y=y||[]).push(t)}},check:E,apply:_,status:function(e){if(!e)return f;s.push(e)},addStatusHandler:function(e){s.push(e)},removeStatusHandler:function(e){var t=s.indexOf(e);t>=0&&s.splice(t,1)},data:i[t]};return n=void 0,r}var s=[],f="idle";function d(e){f=e;for(var t=0;t0;){var o=r.pop(),i=o.id,a=o.chain;if((s=O[i])&&(!s.hot._selfAccepted||s.hot._selfInvalidated)){if(s.hot._selfDeclined)return{type:"self-declined",chain:a,moduleId:i};if(s.hot._main)return{type:"unaccepted",chain:a,moduleId:i};for(var l=0;l ")),T.type){case"self-declined":r.onDeclined&&r.onDeclined(T),r.ignoreDeclined||(_=new Error("Aborted because of self decline: "+T.moduleId+j));break;case"declined":r.onDeclined&&r.onDeclined(T),r.ignoreDeclined||(_=new Error("Aborted because of declined dependency: "+T.moduleId+" in "+T.parentId+j));break;case"unaccepted":r.onUnaccepted&&r.onUnaccepted(T),r.ignoreUnaccepted||(_=new Error("Aborted because "+f+" is not accepted"+j));break;case"accepted":r.onAccepted&&r.onAccepted(T),C=!0;break;case"disposed":r.onDisposed&&r.onDisposed(T),R=!0;break;default:throw new Error("Unexception type "+T.type)}if(_)return d("abort"),Promise.reject(_);if(C)for(f in w[f]=m[f],v(g,T.outdatedModules),T.outdatedDependencies)Object.prototype.hasOwnProperty.call(T.outdatedDependencies,f)&&(b[f]||(b[f]=[]),v(b[f],T.outdatedDependencies[f]));R&&(v(g,[T.moduleId]),w[f]=E)}var D,z=[];for(u=0;u0;)if(f=F.pop(),s=O[f]){var A={},L=s.hot._disposeHandlers;for(c=0;c=0&&U.parents.splice(D,1))}}for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)&&(s=O[f]))for(M=b[f],c=0;c=0&&s.children.splice(D,1);d("apply"),void 0!==h&&(o=h,h=void 0);for(f in m=void 0,w)Object.prototype.hasOwnProperty.call(w,f)&&(e[f]=w[f]);var H=null;for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)&&(s=O[f])){M=b[f];var V=[];for(u=0;ue.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);nN.length&&N.push(e)}function D(e,t,n){return null==e?0:function e(t,n,r,o){var l=typeof t;"undefined"!==l&&"boolean"!==l||(t=null);var u=!1;if(null===t)u=!0;else switch(l){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case i:case a:u=!0}}if(u)return r(o,t,""===n?"."+z(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var c=0;cN.length&&N.push(e)}function D(e,t,n){return null==e?0:function e(t,n,r,o){var l=typeof t;"undefined"!==l&&"boolean"!==l||(t=null);var u=!1;if(null===t)u=!0;else switch(l){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case i:case a:u=!0}}if(u)return r(o,t,""===n?"."+z(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var c=0;c