calificador 0.1.0

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.
@@ -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