calificador 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ # Context that describes an instance method
8
+ class ClassMethodContext < BasicContext
9
+ class Dsl < BasicContext::Dsl
10
+ end
11
+
12
+ attr_reader :method
13
+
14
+ def initialize(parent:, method:, description: nil)
15
+ super(
16
+ parent: parent,
17
+ subject_key: parent.subject_key,
18
+ description: description,
19
+ overrides: {}
20
+ )
21
+
22
+ @method = method
23
+ end
24
+
25
+ def separate_description_by_space?
26
+ @parent && !@parent.is_a?(ExamineContext)
27
+ end
28
+
29
+ def create_subject(environment:, subject_key:)
30
+ subject_key.type
31
+ end
32
+
33
+ def create_result(subject:, arguments:, options:, block:)
34
+ if options.empty?
35
+ subject.send(@method, *arguments, &block)
36
+ else
37
+ subject.send(@method, *arguments, **options, &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Calificador
4
+ module Spec
5
+ class ConditionContext < BasicContext
6
+ class Dsl < BasicContext::Dsl
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ class ExamineContext < BasicContext
8
+ class Dsl < BasicContext::Dsl
9
+ end
10
+
11
+ def initialize(parent:, subject_key:, description:, overrides: {})
12
+ super(
13
+ parent: parent,
14
+ description: description,
15
+ subject_key: subject_key,
16
+ overrides: overrides,
17
+ )
18
+ end
19
+
20
+ def create_subject(environment:, subject_key:)
21
+ environment.create_object(key: subject_key)
22
+ end
23
+
24
+ def subtree_root?
25
+ true
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ # Context that describes an instance method
8
+ class InstanceMethodContext < BasicContext
9
+ class Dsl < BasicContext::Dsl
10
+ end
11
+
12
+ attr_reader :method
13
+
14
+ def initialize(parent:, method:, description: nil)
15
+ super(
16
+ parent: parent,
17
+ subject_key: parent.subject_key,
18
+ description: description,
19
+ overrides: {}
20
+ )
21
+
22
+ @method = method
23
+ end
24
+
25
+ def create_result(subject:, arguments:, options:, block:)
26
+ if options.empty?
27
+ subject.send(@method, *arguments, &block)
28
+ else
29
+ subject.send(@method, *arguments, **options, &block)
30
+ end
31
+ end
32
+
33
+ def separate_description_by_space?
34
+ @parent && !@parent.is_a?(ExamineContext)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ # Environment to run test method
8
+ class TestEnvironment
9
+ def initialize(test:, context:)
10
+ @test = test
11
+ @context = context
12
+ @subject = MISSING
13
+ @call_arguments = []
14
+ @call_options = {}
15
+ @call_block = nil
16
+ @call_result = MISSING
17
+ @created_objects = {}
18
+ @current_assertor = nil
19
+ end
20
+
21
+ def subject(value = MISSING)
22
+ if value.equal?(MISSING)
23
+ if @subject.equal?(MISSING)
24
+ @call_result = MISSING
25
+ @subject = @context.create_subject(environment: self, subject_key: @context.subject_key)
26
+ end
27
+ else
28
+ @call_result = MISSING
29
+ @subject = value
30
+ end
31
+
32
+ @subject
33
+ end
34
+
35
+ def arguments(*arguments, **options, &block)
36
+ @call_arguments = arguments.nil? ? [] : arguments
37
+ @call_options = options.nil? ? {} : options
38
+ @call_block = block
39
+ @call_result = MISSING
40
+ nil
41
+ end
42
+
43
+ def call(*arguments, **options, &block)
44
+ options.empty? ? arguments(*arguments, &block) : arguments(*arguments, **options, &block)
45
+ result
46
+ end
47
+
48
+ def result
49
+ if @call_result == MISSING
50
+ @call_result = @context.create_result(
51
+ subject: subject,
52
+ arguments: @call_arguments,
53
+ options: @call_options,
54
+ block: @call_block
55
+ )
56
+ end
57
+
58
+ @call_result
59
+ end
60
+
61
+ def create(type, trait = nil)
62
+ create_object(key: Key[type, trait])
63
+ end
64
+
65
+ def assert(&block)
66
+ @current_assertor&.__check_triggered
67
+
68
+ @current_assertor = Assertor.new(test: @test, block: block || __default_assert_block)
69
+ end
70
+
71
+ def refute(&block)
72
+ @current_assertor&.__check_triggered
73
+
74
+ @current_assertor = Assertor.new(test: @test, negated: true, block: block || __default_assert_block)
75
+ end
76
+
77
+ def respond_to_missing?(method, include_all)
78
+ @context.lookup_named_factory(name: method) || super
79
+ end
80
+
81
+ def method_missing(method, *arguments, **options, &block)
82
+ factory = @context.lookup_named_factory(name: method)
83
+
84
+ if factory
85
+ create_object(key: factory.key)
86
+ else
87
+ super
88
+ end
89
+ end
90
+
91
+ def create_object(key:)
92
+ @created_objects.fetch(key) do
93
+ factory = @context.lookup_factory(key: key)
94
+
95
+ object = if factory.nil?
96
+ raise(KeyError, "No factory found for #{key}") if key.trait != Key::DEFAULT_TRAIT
97
+
98
+ constructor = key.type.method(:new)
99
+ constructor.invoke
100
+ else
101
+ factory.create(context: self)
102
+ end
103
+
104
+ @created_objects[key] = object
105
+ end
106
+ end
107
+
108
+ def __done
109
+ @current_assertor&.__check_triggered
110
+ end
111
+
112
+ protected
113
+
114
+ def __default_assert_block
115
+ lambda do
116
+ result
117
+ end
118
+ end
119
+
120
+ # def __pass(message = nil)
121
+ # @test.pass(message)
122
+ # end
123
+
124
+ # def __flunk(message = nil)
125
+ # @test.flunk(message)
126
+ # end
127
+
128
+ # def __assert(condition, message = nil)
129
+ # @test.assert(condition, message)
130
+ # end
131
+
132
+ # def __refute(condition, message = nil)
133
+ # @test.refute(condition, message)
134
+ # end
135
+
136
+ # def __exception_details(exception, message)
137
+ # @test.exception_details(exception, message)
138
+ # end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ # Factory class
8
+ class TestMethod < BasicContext
9
+ class Dsl < BasicContext::Dsl
10
+ def body(&block)
11
+ delegate.body = block
12
+ end
13
+ end
14
+
15
+ attr_reader :body, :expected_to_fail
16
+
17
+ def initialize(parent:, subject_key:, description:, overrides:, expected_to_fail: false, body:)
18
+ super(parent: parent, subject_key: subject_key, description: description, overrides: overrides)
19
+
20
+ @body = body
21
+ @expected_to_fail = expected_to_fail
22
+ end
23
+
24
+ def setup
25
+ test_method = self # rubocop:disable Lint/UselessAssignment
26
+ test_method_name = method_name # rubocop:disable Lint/UselessAssignment
27
+ file, line_number = @body.source_location
28
+
29
+ test_class.class_eval(<<~METHOD, file, line_number)
30
+ define_method(test_method_name) do
31
+ __run_test(test_method: test_method)
32
+ end
33
+ METHOD
34
+
35
+ super
36
+ end
37
+
38
+ def method_name
39
+ @method_name ||= "test_: #{full_description}"
40
+ end
41
+
42
+ def run_test(test:)
43
+ body = self.body
44
+ environment = TestEnvironment.new(test: test, context: self)
45
+
46
+ if expected_to_fail
47
+ passed = begin
48
+ environment.instance_exec(&body)
49
+ true
50
+ rescue ::Minitest::Assertion => e
51
+ test.pass(e.message)
52
+ false
53
+ end
54
+
55
+ test.flunk("Expected test to fail") if passed
56
+ else
57
+ environment.instance_exec(&body)
58
+ end
59
+
60
+ environment.__done
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ class TestRoot < ExamineContext
8
+ class Dsl < ExamineContext::Dsl
9
+ def body(&block)
10
+ delegate.body = block
11
+ end
12
+ end
13
+
14
+ attr_accessor :test_class
15
+
16
+ def initialize(test_class:, subject_key:, description:, &body)
17
+ super(parent: nil, subject_key: subject_key, description: description, overrides: {})
18
+
19
+ @test_class = test_class
20
+ @body = body
21
+ end
22
+
23
+ def body=(&block)
24
+ test_class.class_eval(&block)
25
+ end
26
+
27
+ def setup
28
+ setup_body
29
+
30
+ super
31
+ end
32
+
33
+ def create_result(subject:, arguments:, options:, block:)
34
+ subject
35
+ end
36
+
37
+ protected
38
+
39
+ def setup_body
40
+ test_class.class_eval(&@body) if @body
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ class ExamineContext < BasicContext
8
+ class Dsl < BasicContext::Dsl
9
+ end
10
+
11
+ def initialize(parent:, subject_key:, description:, overrides: {})
12
+ super(
13
+ parent: parent,
14
+ description: description,
15
+ subject_key: subject_key,
16
+ overrides: overrides,
17
+ )
18
+ end
19
+
20
+ def create_subject(environment:, subject_key:)
21
+ subject_key.type
22
+ end
23
+
24
+ def subtree_root?
25
+ true
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ using Calificador::Util::CoreExtensions
4
+
5
+ module Calificador
6
+ module Spec
7
+ # Factory calss
8
+ class ValueOverride
9
+ attr_reader :key, :values
10
+
11
+ def initialize(key:, values: {})
12
+ @key = key
13
+ @values = values.dup.freeze
14
+ end
15
+
16
+ def merge(other)
17
+ raise(ArgumentError, "Overrides must have same key") if @key != other.key
18
+
19
+ if other.values.empty? || equal?(other)
20
+ self
21
+ elsif @values.empty?
22
+ other
23
+ else
24
+ ValueOverride.new(key: @key, values: @values.merge(other.values))
25
+ end
26
+ end
27
+
28
+ def merge_values(values)
29
+ if values.empty?
30
+ self
31
+ else
32
+ ValueOverride.new(key: @key, values: @values.merge(values))
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest"
4
+
5
+ using Calificador::Util::CoreExtensions
6
+
7
+ module Calificador
8
+ # Base class for unit tests
9
+ class Test < ::Minitest::Test
10
+ include TestMixin
11
+ end
12
+ end