openhab-jrubyscripting 5.0.0.rc1

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.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/lib/openhab/core/actions.rb +163 -0
  3. data/lib/openhab/core/entity_lookup.rb +144 -0
  4. data/lib/openhab/core/events/abstract_event.rb +17 -0
  5. data/lib/openhab/core/events/item_channel_link.rb +36 -0
  6. data/lib/openhab/core/events/item_command_event.rb +78 -0
  7. data/lib/openhab/core/events/item_event.rb +22 -0
  8. data/lib/openhab/core/events/item_state_changed_event.rb +52 -0
  9. data/lib/openhab/core/events/item_state_event.rb +51 -0
  10. data/lib/openhab/core/events/thing.rb +29 -0
  11. data/lib/openhab/core/events/thing_status_info_event.rb +53 -0
  12. data/lib/openhab/core/events.rb +10 -0
  13. data/lib/openhab/core/items/accepted_data_types.rb +29 -0
  14. data/lib/openhab/core/items/color_item.rb +52 -0
  15. data/lib/openhab/core/items/contact_item.rb +52 -0
  16. data/lib/openhab/core/items/date_time_item.rb +58 -0
  17. data/lib/openhab/core/items/dimmer_item.rb +148 -0
  18. data/lib/openhab/core/items/generic_item.rb +344 -0
  19. data/lib/openhab/core/items/group_item.rb +174 -0
  20. data/lib/openhab/core/items/image_item.rb +109 -0
  21. data/lib/openhab/core/items/location_item.rb +34 -0
  22. data/lib/openhab/core/items/metadata/hash.rb +390 -0
  23. data/lib/openhab/core/items/metadata/namespace_hash.rb +469 -0
  24. data/lib/openhab/core/items/metadata.rb +11 -0
  25. data/lib/openhab/core/items/number_item.rb +62 -0
  26. data/lib/openhab/core/items/numeric_item.rb +22 -0
  27. data/lib/openhab/core/items/persistence.rb +327 -0
  28. data/lib/openhab/core/items/player_item.rb +66 -0
  29. data/lib/openhab/core/items/proxy.rb +59 -0
  30. data/lib/openhab/core/items/registry.rb +66 -0
  31. data/lib/openhab/core/items/rollershutter_item.rb +68 -0
  32. data/lib/openhab/core/items/semantics/enumerable.rb +152 -0
  33. data/lib/openhab/core/items/semantics.rb +476 -0
  34. data/lib/openhab/core/items/state_storage.rb +53 -0
  35. data/lib/openhab/core/items/string_item.rb +28 -0
  36. data/lib/openhab/core/items/switch_item.rb +78 -0
  37. data/lib/openhab/core/items.rb +114 -0
  38. data/lib/openhab/core/lazy_array.rb +52 -0
  39. data/lib/openhab/core/profile_factory.rb +118 -0
  40. data/lib/openhab/core/script_handling.rb +55 -0
  41. data/lib/openhab/core/things/channel.rb +48 -0
  42. data/lib/openhab/core/things/channel_uid.rb +51 -0
  43. data/lib/openhab/core/things/item_channel_link.rb +33 -0
  44. data/lib/openhab/core/things/profile_callback.rb +52 -0
  45. data/lib/openhab/core/things/proxy.rb +69 -0
  46. data/lib/openhab/core/things/registry.rb +46 -0
  47. data/lib/openhab/core/things/thing.rb +194 -0
  48. data/lib/openhab/core/things.rb +22 -0
  49. data/lib/openhab/core/timer.rb +128 -0
  50. data/lib/openhab/core/types/comparable_type.rb +23 -0
  51. data/lib/openhab/core/types/date_time_type.rb +259 -0
  52. data/lib/openhab/core/types/decimal_type.rb +192 -0
  53. data/lib/openhab/core/types/hsb_type.rb +183 -0
  54. data/lib/openhab/core/types/increase_decrease_type.rb +34 -0
  55. data/lib/openhab/core/types/next_previous_type.rb +34 -0
  56. data/lib/openhab/core/types/numeric_type.rb +52 -0
  57. data/lib/openhab/core/types/on_off_type.rb +46 -0
  58. data/lib/openhab/core/types/open_closed_type.rb +41 -0
  59. data/lib/openhab/core/types/percent_type.rb +95 -0
  60. data/lib/openhab/core/types/play_pause_type.rb +38 -0
  61. data/lib/openhab/core/types/point_type.rb +117 -0
  62. data/lib/openhab/core/types/quantity_type.rb +327 -0
  63. data/lib/openhab/core/types/raw_type.rb +26 -0
  64. data/lib/openhab/core/types/refresh_type.rb +27 -0
  65. data/lib/openhab/core/types/rewind_fastforward_type.rb +38 -0
  66. data/lib/openhab/core/types/stop_move_type.rb +34 -0
  67. data/lib/openhab/core/types/string_type.rb +76 -0
  68. data/lib/openhab/core/types/type.rb +117 -0
  69. data/lib/openhab/core/types/un_def_type.rb +38 -0
  70. data/lib/openhab/core/types/up_down_type.rb +50 -0
  71. data/lib/openhab/core/types.rb +69 -0
  72. data/lib/openhab/core/uid.rb +36 -0
  73. data/lib/openhab/core.rb +85 -0
  74. data/lib/openhab/core_ext/java/duration.rb +115 -0
  75. data/lib/openhab/core_ext/java/local_date.rb +93 -0
  76. data/lib/openhab/core_ext/java/local_time.rb +106 -0
  77. data/lib/openhab/core_ext/java/month.rb +59 -0
  78. data/lib/openhab/core_ext/java/month_day.rb +105 -0
  79. data/lib/openhab/core_ext/java/period.rb +103 -0
  80. data/lib/openhab/core_ext/java/temporal_amount.rb +34 -0
  81. data/lib/openhab/core_ext/java/time.rb +58 -0
  82. data/lib/openhab/core_ext/java/unit.rb +15 -0
  83. data/lib/openhab/core_ext/java/zoned_date_time.rb +116 -0
  84. data/lib/openhab/core_ext/ruby/array.rb +21 -0
  85. data/lib/openhab/core_ext/ruby/class.rb +15 -0
  86. data/lib/openhab/core_ext/ruby/date.rb +89 -0
  87. data/lib/openhab/core_ext/ruby/numeric.rb +190 -0
  88. data/lib/openhab/core_ext/ruby/range.rb +70 -0
  89. data/lib/openhab/core_ext/ruby/time.rb +104 -0
  90. data/lib/openhab/core_ext.rb +18 -0
  91. data/lib/openhab/dsl/events/watch_event.rb +18 -0
  92. data/lib/openhab/dsl/events.rb +9 -0
  93. data/lib/openhab/dsl/gems.rb +3 -0
  94. data/lib/openhab/dsl/items/builder.rb +618 -0
  95. data/lib/openhab/dsl/items/ensure.rb +93 -0
  96. data/lib/openhab/dsl/items/timed_command.rb +236 -0
  97. data/lib/openhab/dsl/rules/automation_rule.rb +308 -0
  98. data/lib/openhab/dsl/rules/builder.rb +1373 -0
  99. data/lib/openhab/dsl/rules/guard.rb +115 -0
  100. data/lib/openhab/dsl/rules/name_inference.rb +160 -0
  101. data/lib/openhab/dsl/rules/property.rb +76 -0
  102. data/lib/openhab/dsl/rules/rule_triggers.rb +96 -0
  103. data/lib/openhab/dsl/rules/terse.rb +63 -0
  104. data/lib/openhab/dsl/rules/triggers/changed.rb +169 -0
  105. data/lib/openhab/dsl/rules/triggers/channel.rb +57 -0
  106. data/lib/openhab/dsl/rules/triggers/command.rb +107 -0
  107. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +161 -0
  108. data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +164 -0
  109. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +195 -0
  110. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +127 -0
  111. data/lib/openhab/dsl/rules/triggers/trigger.rb +56 -0
  112. data/lib/openhab/dsl/rules/triggers/updated.rb +130 -0
  113. data/lib/openhab/dsl/rules/triggers/watch/watch.rb +55 -0
  114. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +155 -0
  115. data/lib/openhab/dsl/rules/triggers.rb +12 -0
  116. data/lib/openhab/dsl/rules.rb +29 -0
  117. data/lib/openhab/dsl/script_handling.rb +55 -0
  118. data/lib/openhab/dsl/things/builder.rb +263 -0
  119. data/lib/openhab/dsl/thread_local.rb +48 -0
  120. data/lib/openhab/dsl/timer_manager.rb +191 -0
  121. data/lib/openhab/dsl/version.rb +9 -0
  122. data/lib/openhab/dsl.rb +686 -0
  123. data/lib/openhab/log.rb +348 -0
  124. data/lib/openhab/osgi.rb +70 -0
  125. data/lib/openhab/rspec/configuration.rb +56 -0
  126. data/lib/openhab/rspec/example_group.rb +90 -0
  127. data/lib/openhab/rspec/helpers.rb +439 -0
  128. data/lib/openhab/rspec/hooks.rb +93 -0
  129. data/lib/openhab/rspec/jruby.rb +46 -0
  130. data/lib/openhab/rspec/karaf.rb +811 -0
  131. data/lib/openhab/rspec/mocks/bundle_install_support.rb +25 -0
  132. data/lib/openhab/rspec/mocks/bundle_resolver.rb +30 -0
  133. data/lib/openhab/rspec/mocks/event_admin.rb +146 -0
  134. data/lib/openhab/rspec/mocks/metadata_provider.rb +75 -0
  135. data/lib/openhab/rspec/mocks/persistence_service.rb +140 -0
  136. data/lib/openhab/rspec/mocks/safe_caller.rb +40 -0
  137. data/lib/openhab/rspec/mocks/synchronous_executor.rb +56 -0
  138. data/lib/openhab/rspec/mocks/thing_handler.rb +76 -0
  139. data/lib/openhab/rspec/mocks/timer.rb +95 -0
  140. data/lib/openhab/rspec/openhab/core/actions.rb +26 -0
  141. data/lib/openhab/rspec/openhab/core/items/proxy.rb +27 -0
  142. data/lib/openhab/rspec/openhab/core/things/proxy.rb +27 -0
  143. data/lib/openhab/rspec/shell.rb +31 -0
  144. data/lib/openhab/rspec/suspend_rules.rb +60 -0
  145. data/lib/openhab/rspec.rb +17 -0
  146. data/lib/openhab/yard/cli/stats.rb +23 -0
  147. data/lib/openhab/yard/code_objects/group_object.rb +17 -0
  148. data/lib/openhab/yard/code_objects/java/base.rb +31 -0
  149. data/lib/openhab/yard/code_objects/java/class_object.rb +11 -0
  150. data/lib/openhab/yard/code_objects/java/field_object.rb +15 -0
  151. data/lib/openhab/yard/code_objects/java/interface_object.rb +15 -0
  152. data/lib/openhab/yard/code_objects/java/package_object.rb +11 -0
  153. data/lib/openhab/yard/code_objects/java/proxy.rb +23 -0
  154. data/lib/openhab/yard/handlers/jruby/base.rb +49 -0
  155. data/lib/openhab/yard/handlers/jruby/class_handler.rb +18 -0
  156. data/lib/openhab/yard/handlers/jruby/constant_handler.rb +18 -0
  157. data/lib/openhab/yard/handlers/jruby/java_import_handler.rb +27 -0
  158. data/lib/openhab/yard/handlers/jruby/mixin_handler.rb +23 -0
  159. data/lib/openhab/yard/html_helper.rb +44 -0
  160. data/lib/openhab/yard/tags/constant_directive.rb +20 -0
  161. data/lib/openhab/yard/tags/group_directive.rb +24 -0
  162. data/lib/openhab/yard/tags/library.rb +3 -0
  163. data/lib/openhab/yard.rb +32 -0
  164. metadata +504 -0
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ # @!visibility private
8
+ module Mocks
9
+ class BundleInstallSupport < SimpleDelegator
10
+ include org.apache.karaf.features.internal.service.BundleInstallSupport
11
+
12
+ def initialize(parent, karaf_wrapper)
13
+ super(parent)
14
+ @karaf_wrapper = karaf_wrapper
15
+ end
16
+
17
+ def set_bundle_start_level(bundle, _start_level)
18
+ return if @karaf_wrapper.send(:blocked_bundle?, bundle)
19
+
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ module Mocks
8
+ class BundleResolver
9
+ include org.openhab.core.util.BundleResolver
10
+ include Singleton
11
+
12
+ def initialize
13
+ @classes = {}
14
+ end
15
+
16
+ def register_class(klass, bundle)
17
+ # ensure we have an individual java class already
18
+ @classes[klass.become_java!] = bundle
19
+ end
20
+
21
+ def resolve_bundle(clazz)
22
+ bundle = @classes[clazz]
23
+ return bundle if bundle
24
+
25
+ org.osgi.framework.FrameworkUtil.get_bundle(clazz)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ module Mocks
8
+ # reimplement to not use a thread
9
+ class OSGiEventManager
10
+ attr_reader :logger
11
+
12
+ def initialize(typed_event_factories, typed_event_subscribers)
13
+ @typed_event_factories = typed_event_factories
14
+ @typed_event_subscribers = typed_event_subscribers
15
+ @logger = org.slf4j.LoggerFactory.get_logger("rspec.openhab.core.mocks.event_handler")
16
+ end
17
+
18
+ def handle_event(osgi_event)
19
+ type = osgi_event.get_property("type")
20
+ payload = osgi_event.get_property("payload")
21
+ topic = osgi_event.get_property("topic")
22
+ source = osgi_event.get_property("source")
23
+
24
+ if type.is_a?(String) && payload.is_a?(String) && topic.is_a?(String)
25
+ handle_event_internal(type, payload, topic, source) unless type.empty? || payload.empty? || topic.empty?
26
+ else
27
+ logger.error("The handled OSGi event is invalid. " \
28
+ "Expect properties as string named 'type', 'payload', and 'topic'. " \
29
+ "Received event properties are: #{osgi_event.property_names.inspect}")
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def handle_event_internal(type, payload, topic, source)
36
+ event_factory = @typed_event_factories[type]
37
+ unless event_factory
38
+ logger.debug("Could not find an Event Factory for the event type '#{type}'.")
39
+ return
40
+ end
41
+
42
+ event_subscribers = event_subscribers(type)
43
+ return if event_subscribers.empty?
44
+
45
+ event = create_event(event_factory, type, payload, topic, source)
46
+ return unless event
47
+
48
+ dispatch_event(event_subscribers, event)
49
+ end
50
+
51
+ def event_subscribers(event_type)
52
+ event_type_subscribers = @typed_event_subscribers[event_type]
53
+ all_event_type_subscribers = @typed_event_subscribers["ALL"]
54
+
55
+ subscribers = java.util.HashSet.new
56
+ subscribers.add_all(event_type_subscribers) if event_type_subscribers
57
+ subscribers.add_all(all_event_type_subscribers) if all_event_type_subscribers
58
+ subscribers
59
+ end
60
+
61
+ def create_event(event_factory, type, payload, topic, source)
62
+ event_factory.create_event(type, topic, payload, source)
63
+ rescue Exception => e
64
+ logger.warn("Creation of event failed, because one of the " \
65
+ "registered event factories has thrown an exception: #{e.inspect}")
66
+ nil
67
+ end
68
+
69
+ def dispatch_event(event_subscribers, event)
70
+ event_subscribers.each do |event_subscriber|
71
+ filter = event_subscriber.event_filter
72
+ if filter.nil? || filter.apply(event)
73
+ begin
74
+ event_subscriber.receive(event)
75
+ rescue Exception => e
76
+ logger.warn(
77
+ "Dispatching/filtering event for subscriber '#{event_subscriber.class}' failed: #{e.inspect}"
78
+ )
79
+ end
80
+ else
81
+ logger.trace("Skip event subscriber (#{event_subscriber.class}) because of its filter.")
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ class EventAdmin < org.osgi.util.tracker.ServiceTracker
88
+ include org.osgi.service.event.EventAdmin
89
+
90
+ def initialize(bundle_context)
91
+ super(bundle_context, "org.osgi.service.event.EventHandler", nil)
92
+
93
+ @handlers_matching_all_events = []
94
+ @handlers_matching_topics = Hash.new { |h, k| h[k] = [] }
95
+ open
96
+ end
97
+
98
+ def addingService(reference) # rubocop:disable Naming/MethodName
99
+ topics = Array(reference.get_property(org.osgi.service.event.EventConstants::EVENT_TOPIC))
100
+ topics = nil if topics.empty? || topics.include?("*")
101
+
102
+ service = OSGi.send(:bundle_context).get_service(reference)
103
+
104
+ if reference.get_property("component.name") == "org.openhab.core.internal.events.OSGiEventManager"
105
+ # OSGiEventManager will create a ThreadedEventHandler on OSGi activation;
106
+ # we're skipping that, and directly sending to a non-threaded event handler.
107
+ service.class.field_reader :typedEventFactories, :typedEventSubscribers
108
+ service = OSGiEventManager.new(service.typedEventFactories, service.typedEventSubscribers)
109
+ end
110
+ if topics.nil?
111
+ @handlers_matching_all_events << service
112
+ else
113
+ topics.each do |topic|
114
+ @handlers_matching_topics[topic] << service
115
+ end
116
+ end
117
+ service
118
+ end
119
+
120
+ def postEvent(event) # rubocop:disable Naming/MethodName
121
+ sendEvent(event)
122
+ end
123
+
124
+ def sendEvent(event) # rubocop:disable Naming/MethodName
125
+ # prevent re-entrancy
126
+ if (pending_events = Thread.current[:event_admin_pending_events])
127
+ pending_events << event
128
+ return
129
+ end
130
+
131
+ pending_events = Thread.current[:event_admin_pending_events] = []
132
+ handle_event(event)
133
+ handle_event(pending_events.shift) until pending_events.empty?
134
+ Thread.current[:event_admin_pending_events] = nil
135
+ end
136
+
137
+ private
138
+
139
+ def handle_event(event)
140
+ @handlers_matching_all_events.each { |h| h.handle_event(event) }
141
+ @handlers_matching_topics[event.topic].each { |h| h.handle_event(event) }
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module RSpec
5
+ module Mocks
6
+ class MetadataProvider
7
+ org.openhab.core.common.registry.Identifiable
8
+ include org.openhab.core.items.ManagedMetadataProvider
9
+
10
+ def initialize(parent)
11
+ @metadata = {}
12
+ @listeners = []
13
+ @parent = parent
14
+ @removed_from_parent = []
15
+ end
16
+
17
+ def addProviderChangeListener(listener) # rubocop:disable Naming/MethodName required by java interface
18
+ @listeners << listener
19
+ end
20
+
21
+ def removeProviderChangeListener(listener) # rubocop:disable Naming/MethodName required by java interface
22
+ old = @listeners.delete(listener)
23
+ return unless old
24
+
25
+ @listeners.each { |l| l.removed(self, old) }
26
+ end
27
+
28
+ def add(metadata)
29
+ @metadata[metadata.uid] = metadata
30
+ @listeners.each { |l| l.added(self, metadata) }
31
+ end
32
+
33
+ def update(metadata)
34
+ old_element = @metadata[metadata.uid]
35
+ raise ArgumentError if old_element.nil?
36
+
37
+ @metadata[metadata.uid] = metadata
38
+ @listeners.each { |l| l.updated(self, old_element, metadata) }
39
+ metadata
40
+ end
41
+
42
+ def remove(key)
43
+ m = @parent.remove(key)
44
+ @removed_from_parent << m if m
45
+ m = @metadata.delete(key)
46
+ @listeners.each { |l| l.removed(self, m) } if m
47
+ m
48
+ end
49
+
50
+ def restore_parent
51
+ @removed_from_parent.each do |m|
52
+ @parent.add(m)
53
+ end
54
+ end
55
+
56
+ def get(key)
57
+ @metadata[key]
58
+ end
59
+
60
+ def getAll # rubocop:disable Naming/MethodName required by java interface
61
+ @metadata.values
62
+ end
63
+
64
+ def removeItemMetadata(item_name) # rubocop:disable Naming/MethodName required by java interface
65
+ @metadata.delete_if do |k, v|
66
+ next unless k.item_name == item_name
67
+
68
+ @listeners.each { |l| l.removed(self, v) }
69
+ true
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module RSpec
5
+ module Mocks
6
+ class PersistenceService
7
+ include org.openhab.core.persistence.ModifiablePersistenceService
8
+ include Singleton
9
+
10
+ class HistoricItem
11
+ include org.openhab.core.persistence.HistoricItem
12
+
13
+ attr_reader :timestamp, :state, :name
14
+
15
+ def initialize(timestamp, state, name)
16
+ @timestamp = timestamp
17
+ @state = state
18
+ @name = name
19
+ end
20
+ end
21
+
22
+ attr_reader :id
23
+
24
+ def initialize
25
+ @id = "default"
26
+ reset
27
+ end
28
+
29
+ def reset
30
+ @data = Hash.new { |h, k| h[k] = [] }
31
+ end
32
+
33
+ def store(item, date = nil, state = nil)
34
+ date = nil if date.is_a?(String) # alias overload
35
+ state ||= item.state
36
+ date ||= ZonedDateTime.now
37
+
38
+ new_item = HistoricItem.new(date, state, item.name)
39
+
40
+ item_history = @data[item.name]
41
+
42
+ insert_index = item_history.bsearch_index do |i|
43
+ i.timestamp.compare_to(date).positive?
44
+ end
45
+
46
+ return item_history << new_item unless insert_index
47
+
48
+ return item_history[insert_index].state = state if item_history[insert_index].timestamp == date
49
+
50
+ item_history.insert(insert_index, new_item)
51
+ end
52
+
53
+ def remove(filter)
54
+ query_internal(filter) do |item_history, index|
55
+ historic_item = item_history.delete_at(index)
56
+ @data.delete(historic_item.name) if item_history.empty?
57
+ end
58
+ end
59
+
60
+ def query(filter)
61
+ result = []
62
+
63
+ query_internal(filter) do |item_history, index|
64
+ result << item_history[index]
65
+
66
+ return result if filter.page_number.zero? && result.length == filter.page_size && filter.item_name
67
+ end
68
+
69
+ result.sort_by!(&:timestamp) unless filter.item_name
70
+
71
+ result = result.slice(filter.page_number * filter.page_size, filter.page_size) unless filter.page_number.zero?
72
+
73
+ result
74
+ end
75
+
76
+ def get_item_info # rubocop:disable Naming/AccessorMethodName must match Java interface
77
+ @data.map do |(n, entries)|
78
+ [n, entries.length, entries.first.timestamp, entries.last.timestamp]
79
+ end.to_set
80
+ end
81
+
82
+ def get_default_strategies # rubocop:disable Naming/AccessorMethodName must match Java interface
83
+ [org.openhab.core.persistence.strategy.PersistenceStrategy::Globals::CHANGE]
84
+ end
85
+
86
+ private
87
+
88
+ def query_internal(filter, &block)
89
+ if filter.item_name
90
+ return unless @data.key?(filter.item_name)
91
+
92
+ query_item_internal(@data[filter.item_name], filter, &block)
93
+ else
94
+ @data.each_value do |item_history|
95
+ query_item_internal(item_history, filter, &block)
96
+ end
97
+ end
98
+ end
99
+
100
+ def query_item_internal(item_history, filter)
101
+ first_index = 0
102
+ last_index = item_history.length
103
+
104
+ if filter.begin_date
105
+ first_index = item_history.bsearch_index do |i|
106
+ i.timestamp.compare_to(filter.begin_date).positive?
107
+ end
108
+ return if first_index.nil?
109
+ end
110
+
111
+ if filter.end_date
112
+ last_index = item_history.bsearch_index do |i|
113
+ i.timestamp.compare_to(filter.end_date).positive?
114
+ end
115
+ return if last_index.zero?
116
+
117
+ last_index ||= item_history.length
118
+ end
119
+
120
+ range = first_index...last_index
121
+
122
+ operator = filter.operator.symbol
123
+ operator = "==" if operator == "="
124
+
125
+ block = lambda do |i|
126
+ next if filter.state && !item_history[i].state.send(operator, filter.state)
127
+
128
+ yield(item_history, i)
129
+ end
130
+
131
+ if filter.ordering == filter.class::Ordering::DESCENDING
132
+ range.reverse_each(&block)
133
+ else
134
+ range.each(&block)
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ module Mocks
8
+ class SafeCaller
9
+ include Singleton
10
+ include org.openhab.core.common.SafeCaller
11
+
12
+ class Builder
13
+ include org.openhab.core.common.SafeCallerBuilder
14
+
15
+ def initialize(target)
16
+ @target = target
17
+ end
18
+
19
+ def build
20
+ @target
21
+ end
22
+
23
+ def chain(*)
24
+ self
25
+ end
26
+
27
+ alias_method :withTimeout, :chain
28
+ alias_method :withIdentifier, :chain
29
+ alias_method :onException, :chain
30
+ alias_method :onTimeout, :chain
31
+ alias_method :withAsync, :chain
32
+ end
33
+
34
+ def create(target, _klass)
35
+ Builder.new(target)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ module Mocks
8
+ class CallbacksMap < java.util.HashMap
9
+ def put(_rule_uid, trigger_handler)
10
+ if trigger_handler.executor
11
+ trigger_handler.executor.shutdown_now
12
+ trigger_handler.executor = SynchronousExecutor.instance
13
+ end
14
+ super
15
+ end
16
+ end
17
+
18
+ class SynchronousExecutor < java.util.concurrent.ScheduledThreadPoolExecutor
19
+ class << self
20
+ def instance
21
+ @instance ||= new(1)
22
+ end
23
+ end
24
+
25
+ def submit(runnable)
26
+ runnable.respond_to?(:run) ? runnable.run : runnable.call
27
+
28
+ java.util.concurrent.CompletableFuture.completed_future(nil)
29
+ end
30
+
31
+ def execute(runnable)
32
+ runnable.run
33
+ end
34
+
35
+ def shutdown; end
36
+
37
+ def shutdown_now
38
+ []
39
+ end
40
+ end
41
+
42
+ class SynchronousExecutorMap
43
+ include java.util.Map
44
+ include Singleton
45
+
46
+ def get(_key)
47
+ SynchronousExecutor.instance
48
+ end
49
+
50
+ def key_set
51
+ java.util.HashSet.new
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Naming have to follow java interface names
4
+
5
+ require "singleton"
6
+
7
+ module OpenHAB
8
+ module RSpec
9
+ module Mocks
10
+ class ThingHandler
11
+ include org.openhab.core.thing.binding.BridgeHandler
12
+
13
+ attr_reader :thing, :callback
14
+
15
+ def initialize(thing = nil)
16
+ # have to handle the interface method
17
+ if thing.nil?
18
+ status_info = org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder
19
+ .create(org.openhab.core.thing.ThingStatus::ONLINE).build
20
+ @callback.status_updated(self.thing, status_info)
21
+ return
22
+ end
23
+
24
+ # ruby initializer here
25
+ @thing = thing
26
+ end
27
+
28
+ def thing_updated(thing)
29
+ @thing = thing
30
+ end
31
+
32
+ def handle_command(channel, command); end
33
+
34
+ def set_callback(callback)
35
+ @callback = callback
36
+ end
37
+
38
+ def child_handler_initialized(child_handler, child_thing); end
39
+ def child_handler_disposed(child_handler, child_thing); end
40
+
41
+ def channel_linked(_channel_uid); end
42
+ def channel_unlinked(_channel_uid); end
43
+
44
+ def dispose; end
45
+ end
46
+
47
+ class ThingHandlerFactory < org.openhab.core.thing.binding.BaseThingHandlerFactory
48
+ include Singleton
49
+
50
+ class ComponentContext
51
+ include org.osgi.service.component.ComponentContext
52
+ include Singleton
53
+
54
+ def getBundleContext
55
+ org.osgi.framework.FrameworkUtil.get_bundle(org.openhab.core.thing.Thing).bundle_context
56
+ end
57
+ end
58
+ private_constant :ComponentContext
59
+
60
+ def initialize
61
+ super
62
+ activate(ComponentContext.instance)
63
+ end
64
+
65
+ def supportsThingType(_type)
66
+ true
67
+ end
68
+
69
+ def createHandler(thing)
70
+ ThingHandler.new(thing)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ # rubocop:enable Naming
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timecop"
4
+
5
+ module OpenHAB
6
+ module RSpec
7
+ module Mocks
8
+ class Timer < Core::Timer
9
+ # @!visibility private
10
+ module MockedZonedDateTime
11
+ def now
12
+ mocked_time_stack_item = Timecop.top_stack_item
13
+ return super unless mocked_time_stack_item
14
+
15
+ mocked_time_stack_item.time.to_zoned_date_time
16
+ end
17
+ end
18
+ ZonedDateTime.singleton_class.prepend(MockedZonedDateTime)
19
+
20
+ # extend Timecop to support Java time classes
21
+ # @!visibility private
22
+ module TimeCopStackItem
23
+ def parse_time(*args)
24
+ if args.length == 1
25
+ arg = args.first
26
+ if arg.is_a?(Time) ||
27
+ (defined?(DateTime) && arg.is_a?(DateTime)) ||
28
+ (defined?(Date) && arg.is_a?(Date))
29
+ return super
30
+ elsif arg.respond_to?(:to_zoned_date_time)
31
+ return arg.to_zoned_date_time.to_time
32
+ elsif arg.is_a?(java.time.temporal.TemporalAmount)
33
+ return (ZonedDateTime.now + arg).to_time
34
+ end
35
+ end
36
+
37
+ super
38
+ end
39
+ end
40
+ Timecop::TimeStackItem.prepend(TimeCopStackItem)
41
+
42
+ attr_reader :execution_time, :id, :block
43
+
44
+ def initialize(time, id:, thread_locals:, block:) # rubocop:disable Lint/MissingSuper
45
+ @time = time
46
+ @id = id
47
+ @block = block
48
+ @thread_locals = thread_locals
49
+ reschedule(time)
50
+ end
51
+
52
+ def reschedule(time = nil)
53
+ @execution_time = new_execution_time(time || @time)
54
+ @executed = false
55
+
56
+ DSL::TimerManager.instance.add(self)
57
+
58
+ self
59
+ end
60
+
61
+ def execute
62
+ raise "Timer already cancelled" if cancelled?
63
+ raise "Timer already executed" if terminated?
64
+
65
+ super
66
+ @executed = true
67
+ end
68
+
69
+ def cancel
70
+ return false if terminated? || cancelled?
71
+
72
+ DSL::TimerManager.instance.delete(self)
73
+ @execution_time = nil
74
+ true
75
+ end
76
+
77
+ def cancelled?
78
+ @execution_time.nil?
79
+ end
80
+
81
+ def terminated?
82
+ @executed || cancelled?
83
+ end
84
+
85
+ def running?
86
+ false
87
+ end
88
+
89
+ def active?
90
+ !terminated?
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end