reflekt 0.9.6 → 1.0.1
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/lib/Accessor.rb +9 -10
- data/lib/Aggregator.rb +238 -0
- data/lib/Clone.rb +31 -0
- data/lib/Config.rb +41 -0
- data/lib/Control.rb +53 -14
- data/lib/Execution.rb +48 -7
- data/lib/Meta.rb +39 -0
- data/lib/MetaBuilder.rb +83 -0
- data/lib/Reflection.rb +124 -106
- data/lib/Reflekt.rb +120 -96
- data/lib/Renderer.rb +20 -19
- data/lib/Rule.rb +37 -17
- data/lib/RuleSet.rb +66 -42
- data/lib/ShadowStack.rb +9 -21
- data/lib/meta/ArrayMeta.rb +34 -0
- data/lib/meta/BooleanMeta.rb +26 -0
- data/lib/meta/FloatMeta.rb +26 -0
- data/lib/meta/IntegerMeta.rb +26 -0
- data/lib/meta/StringMeta.rb +26 -0
- data/lib/rules/ArrayRule.rb +88 -0
- data/lib/rules/BooleanRule.rb +45 -0
- data/lib/rules/FloatRule.rb +40 -11
- data/lib/rules/IntegerRule.rb +36 -10
- data/lib/rules/StringRule.rb +60 -8
- data/lib/web/README.md +11 -0
- data/lib/web/bundle.js +30 -0
- data/lib/web/gitignore.txt +7 -0
- data/lib/web/index.html +26 -0
- data/lib/web/package-lock.json +1347 -0
- data/lib/web/package.json +26 -0
- data/lib/web/server.js +118 -0
- metadata +26 -11
- data/lib/Ruler.rb +0 -197
- data/lib/web/script.js +0 -8
- data/lib/web/style.css +0 -151
- data/lib/web/template.html.erb +0 -266
data/lib/Execution.rb
CHANGED
@@ -1,24 +1,65 @@
|
|
1
|
+
################################################################################
|
2
|
+
# A shadow execution.
|
3
|
+
#
|
4
|
+
# @hierachy
|
5
|
+
# 1. Execution <- YOU ARE HERE
|
6
|
+
# 2. Reflection
|
7
|
+
# 3. Meta
|
8
|
+
################################################################################
|
9
|
+
|
1
10
|
class Execution
|
2
11
|
|
3
|
-
attr_accessor :
|
12
|
+
attr_accessor :unique_id
|
13
|
+
attr_accessor :caller_object
|
4
14
|
attr_accessor :caller_id
|
5
15
|
attr_accessor :caller_class
|
16
|
+
attr_accessor :klass
|
17
|
+
attr_accessor :method
|
18
|
+
attr_accessor :base
|
6
19
|
attr_accessor :parent
|
7
20
|
attr_accessor :child
|
8
21
|
attr_accessor :control
|
9
22
|
attr_accessor :reflections
|
10
23
|
attr_accessor :is_reflecting
|
24
|
+
attr_accessor :is_base
|
11
25
|
|
12
|
-
|
26
|
+
##
|
27
|
+
# Create Execution.
|
28
|
+
#
|
29
|
+
# @param object [Object] The calling object.
|
30
|
+
# @param method [Symbol] The calling method.
|
31
|
+
# @param reflect_amount [Integer] The number of reflections to create per execution.
|
32
|
+
# @param stack [ShadowStack] The shadow execution call stack.
|
33
|
+
##
|
34
|
+
def initialize(caller_object, method, reflect_amount, stack)
|
13
35
|
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
36
|
+
@time = Time.now.to_i
|
37
|
+
@unique_id = @time + rand(1..99999)
|
38
|
+
@base = nil
|
17
39
|
@parent = nil
|
18
40
|
@child = nil
|
19
41
|
|
20
|
-
|
21
|
-
@
|
42
|
+
# Dependency.
|
43
|
+
@stack = stack
|
44
|
+
|
45
|
+
# Caller.
|
46
|
+
@caller_object = caller_object
|
47
|
+
@caller_id = caller_object.object_id
|
48
|
+
@caller_class = caller_object.class
|
49
|
+
@klass = @caller_class.to_s.to_sym
|
50
|
+
@method = method
|
51
|
+
|
52
|
+
# Reflections.
|
53
|
+
@control = nil
|
54
|
+
@reflections = Array.new(reflect_amount)
|
55
|
+
|
56
|
+
# State.
|
57
|
+
if @stack.peek() == nil
|
58
|
+
@is_base = true
|
59
|
+
else
|
60
|
+
@is_base = false
|
61
|
+
@base = @stack.base()
|
62
|
+
end
|
22
63
|
@is_reflecting = false
|
23
64
|
|
24
65
|
end
|
data/lib/Meta.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Metadata for input and output.
|
3
|
+
#
|
4
|
+
# @pattern Abstract class
|
5
|
+
# @see lib/meta for each meta.
|
6
|
+
#
|
7
|
+
# @hierachy
|
8
|
+
# 1. Execution
|
9
|
+
# 2. Reflection
|
10
|
+
# 3. Meta <- YOU ARE HERE
|
11
|
+
################################################################################
|
12
|
+
|
13
|
+
class Meta
|
14
|
+
|
15
|
+
##
|
16
|
+
# Each meta defines its type.
|
17
|
+
##
|
18
|
+
def initialize()
|
19
|
+
@type = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Each meta loads values.
|
24
|
+
#
|
25
|
+
# @param value [Dynamic]
|
26
|
+
##
|
27
|
+
def load(value)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Each meta provides metadata.
|
32
|
+
#
|
33
|
+
# @return [Hash]
|
34
|
+
##
|
35
|
+
def result()
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/lib/MetaBuilder.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Create metadata.
|
3
|
+
#
|
4
|
+
# @pattern Builder
|
5
|
+
# @see lib/meta for each meta.
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'Meta'
|
9
|
+
# Require all meta.
|
10
|
+
Dir[File.join(__dir__, 'meta', '*.rb')].each { |file| require file }
|
11
|
+
|
12
|
+
class MetaBuilder
|
13
|
+
|
14
|
+
##
|
15
|
+
# Create meta.
|
16
|
+
#
|
17
|
+
# @param value
|
18
|
+
##
|
19
|
+
def self.create(value)
|
20
|
+
|
21
|
+
meta = nil
|
22
|
+
data_type = value.class.to_s
|
23
|
+
|
24
|
+
# Create meta type for matching data type.
|
25
|
+
case data_type
|
26
|
+
when "Array"
|
27
|
+
meta = ArrayMeta.new()
|
28
|
+
when "TrueClass", "FalseClass"
|
29
|
+
meta = BooleanMeta.new()
|
30
|
+
when "Float"
|
31
|
+
meta = FloatMeta.new()
|
32
|
+
when "Integer"
|
33
|
+
meta = IntegerMeta.new()
|
34
|
+
when "String"
|
35
|
+
meta = StringMeta.new()
|
36
|
+
end
|
37
|
+
|
38
|
+
unless meta.nil?
|
39
|
+
meta.load(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
return meta
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Create meta for multiple values.
|
48
|
+
#
|
49
|
+
# @param values
|
50
|
+
##
|
51
|
+
def self.create_many(values)
|
52
|
+
|
53
|
+
meta = []
|
54
|
+
|
55
|
+
values.each do |value|
|
56
|
+
meta << self.create(value)
|
57
|
+
end
|
58
|
+
|
59
|
+
return meta
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# @param data_type [Type]
|
65
|
+
##
|
66
|
+
def self.data_type_to_meta_type(value)
|
67
|
+
|
68
|
+
data_type = value.class
|
69
|
+
|
70
|
+
meta_types = {
|
71
|
+
Array => :array,
|
72
|
+
TrueClass => :bool,
|
73
|
+
FalseClass => :bool,
|
74
|
+
Float => :float,
|
75
|
+
Integer => :int,
|
76
|
+
String => :string
|
77
|
+
}
|
78
|
+
|
79
|
+
return meta_types[data_type]
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/Reflection.rb
CHANGED
@@ -1,167 +1,185 @@
|
|
1
|
+
################################################################################
|
2
|
+
# A snapshot of simulated data.
|
3
|
+
#
|
4
|
+
# @nomenclature
|
5
|
+
# args, inputs/output and meta represent different stages of a value.
|
6
|
+
#
|
7
|
+
# @hierachy
|
8
|
+
# 1. Execution
|
9
|
+
# 2. Reflection <- YOU ARE HERE
|
10
|
+
# 3. Meta
|
11
|
+
################################################################################
|
12
|
+
|
13
|
+
require 'Clone'
|
14
|
+
require 'MetaBuilder'
|
15
|
+
|
1
16
|
class Reflection
|
2
17
|
|
3
|
-
|
4
|
-
TIME = "t"
|
5
|
-
INPUT = "i"
|
6
|
-
OUTPUT = "o"
|
7
|
-
TYPE = "T"
|
8
|
-
COUNT = "C"
|
9
|
-
VALUE = "V"
|
10
|
-
STATUS = "s"
|
11
|
-
MESSAGE = "m"
|
12
|
-
# Values.
|
13
|
-
PASS = "p"
|
14
|
-
FAIL = "f"
|
15
|
-
|
16
|
-
attr_accessor :clone
|
18
|
+
attr_reader :status
|
17
19
|
|
18
20
|
##
|
19
21
|
# Create a Reflection.
|
20
22
|
#
|
21
|
-
# @
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
23
|
+
# @status
|
24
|
+
# - :pass The reflection passes the rules.
|
25
|
+
# - :fail The reflection fails the rules or produces a system error.
|
26
|
+
# - :error The control reflection produces a system error.
|
27
|
+
#
|
28
|
+
# @param execution [Execution] The Execution that created this Reflection.
|
29
|
+
# @param number [Integer] Multiple Reflections can be created per Execution.
|
30
|
+
# @param aggregator [Aggregator] The aggregated RuleSet for this class/method.
|
25
31
|
##
|
26
|
-
def initialize(execution,
|
32
|
+
def initialize(execution, number, aggregator)
|
27
33
|
|
28
34
|
@execution = execution
|
29
|
-
@
|
30
|
-
@
|
31
|
-
|
35
|
+
@unique_id = execution.unique_id + number
|
36
|
+
@number = number
|
37
|
+
|
38
|
+
# Dependency.
|
39
|
+
@aggregator = aggregator
|
32
40
|
|
33
|
-
#
|
34
|
-
@
|
41
|
+
# Caller.
|
42
|
+
@klass = execution.klass
|
43
|
+
@method = execution.method
|
44
|
+
|
45
|
+
# Metadata.
|
46
|
+
@inputs = nil
|
35
47
|
@output = nil
|
36
48
|
|
37
|
-
# Clone the execution's object.
|
38
|
-
|
39
|
-
@
|
49
|
+
# Clone the execution's calling object.
|
50
|
+
# TODO: Abstract away into Clone class.
|
51
|
+
@clone = execution.caller_object.clone
|
40
52
|
|
41
53
|
# Result.
|
42
|
-
@status =
|
54
|
+
@status = :pass
|
43
55
|
@time = Time.now.to_i
|
56
|
+
@message = nil
|
44
57
|
|
45
58
|
end
|
46
59
|
|
47
60
|
##
|
48
61
|
# Reflect on a method.
|
49
62
|
#
|
50
|
-
# Creates a shadow execution
|
51
|
-
#
|
52
|
-
# @param *args - The method's arguments.
|
53
|
-
#
|
54
|
-
# @return - A reflection hash.
|
63
|
+
# Creates a shadow execution.
|
64
|
+
# @param *args [Dynamic] The method's arguments.
|
55
65
|
##
|
56
66
|
def reflect(*args)
|
57
67
|
|
58
|
-
# Get
|
59
|
-
input_rule_sets = @
|
60
|
-
output_rule_set = @
|
61
|
-
|
62
|
-
# Create deviated arguments.
|
63
|
-
args.each do |arg|
|
64
|
-
case arg
|
65
|
-
when Integer
|
66
|
-
@inputs << rand(999)
|
67
|
-
else
|
68
|
-
@inputs << arg
|
69
|
-
end
|
70
|
-
end
|
68
|
+
# Get aggregated rule sets.
|
69
|
+
input_rule_sets = @aggregator.get_input_rule_sets(@klass, @method)
|
70
|
+
output_rule_set = @aggregator.get_output_rule_set(@klass, @method)
|
71
71
|
|
72
|
-
#
|
73
|
-
|
72
|
+
# When arguments exist.
|
73
|
+
unless args.size == 0
|
74
74
|
|
75
|
-
#
|
75
|
+
# When aggregated rule sets exist.
|
76
76
|
unless input_rule_sets.nil?
|
77
|
-
|
78
|
-
|
77
|
+
|
78
|
+
# Randomize arguments from rule sets.
|
79
|
+
args = randomize(args, input_rule_sets)
|
80
|
+
|
81
|
+
# Validate arguments against aggregated rule sets.
|
82
|
+
unless @aggregator.test_inputs(args, input_rule_sets)
|
83
|
+
@status = :fail
|
79
84
|
end
|
85
|
+
|
80
86
|
end
|
81
87
|
|
88
|
+
# Create metadata for each argument.
|
89
|
+
# TODO: Create metadata for other inputs such as properties on the instance.
|
90
|
+
@inputs = MetaBuilder.create_many(args)
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
# Action method with new/old arguments.
|
95
|
+
begin
|
96
|
+
|
82
97
|
# Run reflection.
|
83
|
-
|
98
|
+
output = @clone.send(@method, *args)
|
99
|
+
@output = MetaBuilder.create(output)
|
84
100
|
|
85
|
-
# Validate output with
|
101
|
+
# Validate output with aggregated control rule sets.
|
86
102
|
unless output_rule_set.nil?
|
87
|
-
unless @
|
88
|
-
@status =
|
103
|
+
unless @aggregator.test_output(output, output_rule_set)
|
104
|
+
@status = :fail
|
89
105
|
end
|
90
106
|
end
|
91
107
|
|
92
|
-
# When
|
108
|
+
# When a system error occurs.
|
93
109
|
rescue StandardError => message
|
94
|
-
|
110
|
+
|
111
|
+
@status = :fail
|
95
112
|
@message = message
|
113
|
+
|
96
114
|
end
|
97
115
|
|
98
116
|
end
|
99
117
|
|
100
|
-
def result()
|
101
|
-
# Build reflection.
|
102
|
-
reflection = {
|
103
|
-
TIME => @time,
|
104
|
-
STATUS => @status,
|
105
|
-
INPUT => normalize_input(@inputs),
|
106
|
-
OUTPUT => normalize_output(@output),
|
107
|
-
MESSAGE => @message
|
108
|
-
}
|
109
|
-
end
|
110
|
-
|
111
118
|
##
|
112
|
-
#
|
119
|
+
# Create random values for each argument from control reflections.
|
120
|
+
#
|
121
|
+
# @param args [Dynamic] The arguments to create random values for.
|
122
|
+
# @param input_rule_sets [Array] Aggregated rule sets for each argument.
|
113
123
|
#
|
114
|
-
# @
|
115
|
-
# @return - A generic inputs representation.
|
124
|
+
# @return [Dynamic] Random arguments.
|
116
125
|
##
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
126
|
+
def randomize(args, input_rule_sets)
|
127
|
+
|
128
|
+
random_args = []
|
129
|
+
|
130
|
+
args.each_with_index do |arg, arg_num|
|
131
|
+
|
132
|
+
rule_type = Aggregator.value_to_rule_type(arg)
|
133
|
+
agg_rule = input_rule_sets[arg_num].rules[rule_type]
|
134
|
+
|
135
|
+
random_args << agg_rule.random()
|
136
|
+
|
128
137
|
end
|
129
|
-
|
138
|
+
|
139
|
+
return random_args
|
140
|
+
|
130
141
|
end
|
131
142
|
|
132
143
|
##
|
133
|
-
#
|
144
|
+
# Get the results of the reflection.
|
134
145
|
#
|
135
|
-
# @
|
136
|
-
# @return - A generic output representation.
|
146
|
+
# @return [Hash] Reflection metadata.
|
137
147
|
##
|
138
|
-
def
|
139
|
-
|
140
|
-
output = {
|
141
|
-
TYPE => input.class.to_s,
|
142
|
-
VALUE => normalize_value(input)
|
143
|
-
}
|
148
|
+
def result()
|
144
149
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
150
|
+
# The ID of the first execution in the ShadowStack.
|
151
|
+
base_id = nil
|
152
|
+
unless @execution.base == nil
|
153
|
+
base_id = @execution.base.unique_id
|
149
154
|
end
|
150
155
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
+
# Build reflection.
|
157
|
+
reflection = {
|
158
|
+
:base_id => base_id,
|
159
|
+
:exe_id => @execution.unique_id,
|
160
|
+
:ref_id => @unique_id,
|
161
|
+
:ref_num => @number,
|
162
|
+
:time => @time,
|
163
|
+
:class => @klass,
|
164
|
+
:method => @method,
|
165
|
+
:status => @status,
|
166
|
+
:message => @message,
|
167
|
+
:inputs => nil,
|
168
|
+
:output => nil,
|
169
|
+
}
|
156
170
|
|
157
|
-
unless
|
158
|
-
|
159
|
-
|
160
|
-
|
171
|
+
unless @inputs.nil?
|
172
|
+
reflection[:inputs] = []
|
173
|
+
@inputs.each do |meta|
|
174
|
+
reflection[:inputs] << meta.result()
|
161
175
|
end
|
162
176
|
end
|
163
177
|
|
164
|
-
|
178
|
+
unless @output.nil?
|
179
|
+
reflection[:output] = @output.result()
|
180
|
+
end
|
181
|
+
|
182
|
+
return reflection
|
165
183
|
|
166
184
|
end
|
167
185
|
|