bugsnag-maze-runner 6.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bugsnag-print-load-paths +6 -0
  3. data/bin/download-logs +76 -0
  4. data/bin/maze-runner +136 -0
  5. data/bin/upload-app +56 -0
  6. data/lib/features/scripts/await-android-emulator.sh +11 -0
  7. data/lib/features/scripts/clear-android-app-data.sh +8 -0
  8. data/lib/features/scripts/force-stop-android-app.sh +8 -0
  9. data/lib/features/scripts/install-android-app.sh +15 -0
  10. data/lib/features/scripts/launch-android-app.sh +38 -0
  11. data/lib/features/scripts/launch-android-emulator.sh +15 -0
  12. data/lib/features/steps/android_steps.rb +51 -0
  13. data/lib/features/steps/app_automator_steps.rb +228 -0
  14. data/lib/features/steps/aws_sam_steps.rb +212 -0
  15. data/lib/features/steps/breadcrumb_steps.rb +50 -0
  16. data/lib/features/steps/browser_steps.rb +93 -0
  17. data/lib/features/steps/build_api_steps.rb +25 -0
  18. data/lib/features/steps/document_server_steps.rb +7 -0
  19. data/lib/features/steps/error_reporting_steps.rb +342 -0
  20. data/lib/features/steps/feature_flag_steps.rb +190 -0
  21. data/lib/features/steps/header_steps.rb +72 -0
  22. data/lib/features/steps/log_steps.rb +29 -0
  23. data/lib/features/steps/multipart_request_steps.rb +142 -0
  24. data/lib/features/steps/network_steps.rb +75 -0
  25. data/lib/features/steps/payload_steps.rb +234 -0
  26. data/lib/features/steps/proxy_steps.rb +34 -0
  27. data/lib/features/steps/query_parameter_steps.rb +31 -0
  28. data/lib/features/steps/request_assertion_steps.rb +107 -0
  29. data/lib/features/steps/runner_steps.rb +406 -0
  30. data/lib/features/steps/session_tracking_steps.rb +116 -0
  31. data/lib/features/steps/value_steps.rb +119 -0
  32. data/lib/features/support/env.rb +7 -0
  33. data/lib/features/support/internal_hooks.rb +260 -0
  34. data/lib/maze/appium_server.rb +112 -0
  35. data/lib/maze/assertions/request_set_assertions.rb +97 -0
  36. data/lib/maze/aws/sam.rb +112 -0
  37. data/lib/maze/bitbar_devices.rb +84 -0
  38. data/lib/maze/bitbar_utils.rb +112 -0
  39. data/lib/maze/browser_stack_devices.rb +160 -0
  40. data/lib/maze/browser_stack_utils.rb +164 -0
  41. data/lib/maze/browsers_bs.yml +220 -0
  42. data/lib/maze/browsers_cbt.yml +100 -0
  43. data/lib/maze/bugsnag_config.rb +42 -0
  44. data/lib/maze/capabilities.rb +126 -0
  45. data/lib/maze/checks/assert_check.rb +91 -0
  46. data/lib/maze/checks/noop_check.rb +34 -0
  47. data/lib/maze/compare.rb +161 -0
  48. data/lib/maze/configuration.rb +174 -0
  49. data/lib/maze/docker.rb +108 -0
  50. data/lib/maze/document_server.rb +46 -0
  51. data/lib/maze/driver/appium.rb +217 -0
  52. data/lib/maze/driver/browser.rb +138 -0
  53. data/lib/maze/driver/resilient_appium.rb +51 -0
  54. data/lib/maze/errors.rb +20 -0
  55. data/lib/maze/helper.rb +118 -0
  56. data/lib/maze/hooks/appium_hooks.rb +216 -0
  57. data/lib/maze/hooks/browser_hooks.rb +68 -0
  58. data/lib/maze/hooks/command_hooks.rb +9 -0
  59. data/lib/maze/hooks/hooks.rb +61 -0
  60. data/lib/maze/interactive_cli.rb +173 -0
  61. data/lib/maze/logger.rb +73 -0
  62. data/lib/maze/macos_utils.rb +14 -0
  63. data/lib/maze/network.rb +49 -0
  64. data/lib/maze/option/parser.rb +245 -0
  65. data/lib/maze/option/processor.rb +143 -0
  66. data/lib/maze/option/validator.rb +184 -0
  67. data/lib/maze/option.rb +64 -0
  68. data/lib/maze/plugins/bugsnag_reporting_plugin.rb +49 -0
  69. data/lib/maze/plugins/cucumber_report_plugin.rb +101 -0
  70. data/lib/maze/plugins/global_retry_plugin.rb +38 -0
  71. data/lib/maze/proxy.rb +114 -0
  72. data/lib/maze/request_list.rb +82 -0
  73. data/lib/maze/retry_handler.rb +76 -0
  74. data/lib/maze/runner.rb +149 -0
  75. data/lib/maze/sauce_labs_utils.rb +96 -0
  76. data/lib/maze/server.rb +207 -0
  77. data/lib/maze/servlets/base_servlet.rb +22 -0
  78. data/lib/maze/servlets/command_servlet.rb +44 -0
  79. data/lib/maze/servlets/log_servlet.rb +64 -0
  80. data/lib/maze/servlets/reflective_servlet.rb +69 -0
  81. data/lib/maze/servlets/servlet.rb +160 -0
  82. data/lib/maze/smart_bear_utils.rb +71 -0
  83. data/lib/maze/store.rb +15 -0
  84. data/lib/maze/terminating_server.rb +129 -0
  85. data/lib/maze/timers.rb +51 -0
  86. data/lib/maze/wait.rb +35 -0
  87. data/lib/maze.rb +27 -0
  88. metadata +371 -0
@@ -0,0 +1,100 @@
1
+ # Selenium capabilities for browserNames available on CrossbrowserNameTesting
2
+ ---
3
+ ie_8:
4
+ browserName: "Internet Explorer"
5
+ version: "8"
6
+ platform: "Windows 7"
7
+
8
+ ie_9:
9
+ browserName: "Internet Explorer"
10
+ version: "9"
11
+ platform: "Windows 7"
12
+
13
+ ie_10:
14
+ browserName: "Internet Explorer"
15
+ version: "10"
16
+ os: "windows"
17
+ platform: "Windows 7 64-Bit"
18
+
19
+ ie_11:
20
+ browserName: "Internet Explorer"
21
+ version: "11"
22
+ platform: "Windows 7 64-Bit"
23
+
24
+ edge_14:
25
+ browserName: "MicrosoftEdge"
26
+ version: "14"
27
+ platform: "Windows 10"
28
+
29
+ edge_15:
30
+ browserName: "MicrosoftEdge"
31
+ version: "15"
32
+ platform: "Windows 10"
33
+
34
+ safari_8:
35
+ browserName: "Safari"
36
+ version: "8"
37
+ platform: "Mac OSX 10.10"
38
+
39
+ safari_10:
40
+ browserName: "Safari"
41
+ version: "10"
42
+ platform: "Mac OSX 10.12"
43
+
44
+ safari_13:
45
+ browserName: "Safari"
46
+ version: "13"
47
+ platform: "Mac OSX 10.15"
48
+
49
+ safari_14:
50
+ browserName: "Safari"
51
+ version: "14"
52
+ platform: "MacOS 11.0"
53
+
54
+ iphone_7_simulator:
55
+ browserName: "Safari"
56
+ deviceName: "iPhone 7 Simulator"
57
+ platformVersion': "10.0"
58
+ platformName': "iOS"
59
+
60
+ iphone_xr:
61
+ browserName: "Safari"
62
+ deviceName': "iPhone XR"
63
+ platformVersion': "12.1"
64
+ platformName': "iOS"
65
+
66
+ android_s7:
67
+ browserName: "Chrome"
68
+ deviceName: "Galaxy S7"
69
+ platformVersion: "7.0"
70
+ platformName: "Android"
71
+
72
+ firefox_30:
73
+ browserName: "Firefox"
74
+ version: "30"
75
+ platform: "Windows 7"
76
+
77
+ firefox_56:
78
+ browserName: "Firefox"
79
+ version: "56"
80
+ platform: "Mac OSX 10.13"
81
+
82
+ firefox_95:
83
+ browserName: "Firefox"
84
+ version: "95"
85
+ platform: "Windows 10"
86
+
87
+ chrome_43:
88
+ browserName: "Chrome"
89
+ version: "43"
90
+ platform: "Windows 7"
91
+
92
+ chrome_61:
93
+ browserName: "Chrome"
94
+ version: "61"
95
+ platform: "Windows 10"
96
+
97
+ chrome_96:
98
+ browserName: "Chrome"
99
+ version: "96"
100
+ platform: "Windows 10"
@@ -0,0 +1,42 @@
1
+ require 'bugsnag'
2
+
3
+ # Contains logic for running Bugsnag
4
+ module Maze
5
+ class BugsnagConfig
6
+ class << self
7
+ def start_bugsnag(cucumber_config)
8
+ # Use MAZE_BUGSNAG_API_KEY explicitly to avoid collisions with test env
9
+ return unless Maze.config.enable_bugsnag && ENV['MAZE_BUGSNAG_API_KEY']
10
+
11
+ Bugsnag.configure do |config|
12
+ config.api_key = ENV['MAZE_BUGSNAG_API_KEY']
13
+ config.discard_classes << 'Test::Unit::AssertionFailedError'
14
+ config.add_metadata(:'test driver', {
15
+ 'driver type': Maze.driver.class,
16
+ 'device farm': Maze.config.farm,
17
+ 'capabilities': Maze.config.capabilities
18
+ }) if Maze.driver
19
+ config.add_metadata(:'buildkite', {
20
+ 'pipeline': ENV['BUILDKITE_PIPELINE_NAME'],
21
+ 'repo': ENV['BUILDKITE_REPO'],
22
+ 'build url': ENV['BUILDKITE_BUILD_URL'],
23
+ 'branch': ENV['BUILDKITE_BRANCH'],
24
+ 'builder': ENV['BUILDKITE_BUILD_CREATOR'],
25
+ 'message': ENV['BUILDKITE_MESSAGE'],
26
+ 'step': ENV['BUILDKITE_LABEL']
27
+ }) if ENV['BUILDKITE']
28
+ config.project_root = Dir.pwd
29
+ end
30
+
31
+ Bugsnag.start_session
32
+
33
+ at_exit do
34
+ if $!
35
+ Bugsnag.notify($!)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ # Appium capabilities for each target farm
5
+ class Capabilities
6
+ class << self
7
+ # @param device_type [String] A key from @see BrowserStackDevices::DEVICE_HASH
8
+ # @param local_id [String] unique key for the tunnel instance
9
+ # @param capabilities_option [String] extra capabilities provided on the command line
10
+ def for_browser_stack_device(device_type, local_id, appium_version, capabilities_option)
11
+ capabilities = {
12
+ 'browserstack.console' => 'errors',
13
+ 'browserstack.localIdentifier' => local_id,
14
+ 'browserstack.local' => 'true',
15
+ 'noReset' => 'true'
16
+ }
17
+ capabilities.merge! BrowserStackDevices::DEVICE_HASH[device_type]
18
+ capabilities.merge! JSON.parse(capabilities_option)
19
+ capabilities['browserstack.appium_version'] = appium_version unless appium_version.nil?
20
+ capabilities
21
+ end
22
+
23
+ # @param browser_type [String] A key from @see browsers_bs.yml
24
+ # @param local_id [String] unique key for the tunnel instance
25
+ # @param capabilities_option [String] extra capabilities provided on the command line
26
+ def for_browser_stack_browser(browser_type, local_id, capabilities_option)
27
+ capabilities = Selenium::WebDriver::Remote::Capabilities.new
28
+ capabilities['browserstack.local'] = 'true'
29
+ capabilities['browserstack.localIdentifier'] = local_id
30
+ capabilities['browserstack.console'] = 'errors'
31
+ browsers = YAML.safe_load(File.read("#{__dir__}/browsers_bs.yml"))
32
+ capabilities.merge! browsers[browser_type]
33
+ capabilities.merge! JSON.parse(capabilities_option)
34
+ capabilities
35
+ end
36
+
37
+ # @param browser_type [String] A key from @see browsers_cbt.yml
38
+ # @param local_id [String] unique key for the SB tunnel instance
39
+ # @param capabilities_option [String] extra capabilities provided on the command line
40
+ def for_cbt_browser(browser_type, local_id, capabilities_option)
41
+ capabilities = Selenium::WebDriver::Remote::Capabilities.new
42
+ capabilities['tunnel_name'] = local_id
43
+ browsers = YAML.safe_load(File.read("#{__dir__}/browsers_cbt.yml"))
44
+ capabilities.merge! browsers[browser_type]
45
+ capabilities.merge! JSON.parse(capabilities_option)
46
+ capabilities
47
+ end
48
+
49
+ # @param device_type [String]
50
+ def for_bitbar_device(bitbar_api_key, device_type, platform, platform_version, capabilities_option)
51
+ capabilities = {
52
+ 'bitbar_apiKey' => bitbar_api_key,
53
+ 'bitbar_testrun' => "#{platform} #{platform_version}",
54
+ 'bitbar_findDevice' => false,
55
+ 'bitbar_testTimeout' => 7200,
56
+ 'disabledAnimations' => 'true',
57
+ 'noReset' => 'true'
58
+ }
59
+ capabilities.merge! BitBarDevices.get_device(device_type, platform, platform_version, bitbar_api_key)
60
+ capabilities.merge! JSON.parse(capabilities_option)
61
+ capabilities
62
+ end
63
+
64
+ # Constructs Appium capabilities for running on a local Android or iOS device.
65
+ # @param platform [String] 'ios' or 'android'
66
+ # @param capabilities_option [String] extra capabilities provided on the command line
67
+ # @param team_id [String] Apple Team Id, for iOS only
68
+ # @param udid [String] device UDID, for iOS only
69
+ # noinspection RubyStringKeysInHashInspection
70
+ def for_local(platform, capabilities_option, team_id = nil, udid = nil)
71
+ capabilities = case platform.downcase
72
+ when 'android'
73
+ {
74
+ 'platformName' => 'Android',
75
+ 'automationName' => 'UiAutomator2',
76
+ 'autoGrantPermissions' => 'true',
77
+ 'noReset' => 'true'
78
+ }
79
+ when 'ios'
80
+ {
81
+ 'platformName' => 'iOS',
82
+ 'automationName' => 'XCUITest',
83
+ 'deviceName' => udid,
84
+ 'xcodeOrgId' => team_id,
85
+ 'xcodeSigningId' => 'iPhone Developer',
86
+ 'udid' => udid,
87
+ 'noReset' => 'true',
88
+ 'waitForQuiescence' => false,
89
+ 'newCommandTimeout' => 0
90
+ }
91
+ when 'macos'
92
+ {
93
+ 'platformName' => 'Mac'
94
+ }
95
+ else
96
+ raise "Unsupported platform: #{platform}"
97
+ end
98
+ common = {
99
+ 'os' => platform,
100
+ 'autoAcceptAlerts': 'true'
101
+ }
102
+ capabilities.merge! common
103
+ capabilities.merge! JSON.parse(capabilities_option)
104
+ end
105
+
106
+ def for_sauce_labs_device(device_name, os, os_version, tunnel_id, appium_version, capabilities_option)
107
+ capabilities = {
108
+ 'noReset' => true,
109
+ 'deviceOrientation' => 'portrait',
110
+ 'tunnelIdentifier' => tunnel_id,
111
+ 'browserName' => '',
112
+ 'autoAcceptAlerts' => true,
113
+ 'sendKeyStrategy' => 'setValue',
114
+ 'waitForQuiescence' => false,
115
+ 'newCommandTimeout' => 0
116
+ }
117
+ capabilities['deviceName'] = device_name unless device_name.nil?
118
+ capabilities['platformName'] = os unless os.nil?
119
+ capabilities['platformVersion'] = os_version unless os_version.nil?
120
+ capabilities.merge! JSON.parse(capabilities_option)
121
+ capabilities['appiumVersion'] = appium_version unless appium_version.nil?
122
+ capabilities
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+ require 'test/unit'
3
+
4
+ module Maze
5
+ module Checks
6
+ # Assertion-backed data verification checks
7
+ class AssertCheck
8
+ include Test::Unit::Assertions
9
+
10
+ def true(test, message = nil)
11
+ assert_true(test, message)
12
+ end
13
+
14
+ def false(test, message = nil)
15
+ assert_false(test, message)
16
+ end
17
+
18
+ def nil(test, message = nil)
19
+ assert_nil(test, message)
20
+ end
21
+
22
+ def not_nil(test, message = nil)
23
+ assert_not_nil(test, message)
24
+ end
25
+
26
+ def match(pattern, string, message = nil)
27
+ assert_match(pattern, string, message)
28
+ end
29
+
30
+ def equal(expected, act, message = nil)
31
+ assert_equal(expected, act, message)
32
+ end
33
+
34
+ def not_equal(expected, act, message = nil)
35
+ assert_not_equal(expected, act, message)
36
+ end
37
+
38
+ def operator(operand1, operator, operand2, message = nil)
39
+ assert_operator(operand1, operator, operand2, message)
40
+ end
41
+
42
+ def kind_of(klass, object, message = nil)
43
+ assert_kind_of(klass, object, message)
44
+ end
45
+
46
+ def block(message = 'block failed', &block)
47
+ assert_block(message, &block)
48
+ end
49
+
50
+ def include(collection, object, message = nil)
51
+ assert_include(collection, object, message)
52
+ end
53
+ alias includes include
54
+
55
+ def not_include(collection, object, message = nil)
56
+ assert_not_include(collection, object, message)
57
+ end
58
+ alias not_includes not_include
59
+ end
60
+ end
61
+ end
62
+
63
+ # Wrapper for Maze.check.true to avoid making a breaking change.
64
+ # @deprecated TODO Remove in v7
65
+ def assert_true(value, message = nil)
66
+ Maze.check.true value, message
67
+ end
68
+
69
+ # Wrapper for Maze.check.false to avoid making a breaking change.
70
+ # @deprecated TODO Remove in v7
71
+ def assert_false(value, message = nil)
72
+ Maze.check.false value, message
73
+ end
74
+
75
+ # Wrapper for Maze.check.not_nil to avoid making a breaking change.
76
+ # @deprecated TODO Remove in v7
77
+ def assert_not_nil(value, message = nil)
78
+ Maze.check.not_nil value, message
79
+ end
80
+
81
+ # Wrapper for Maze.check.not_nil to avoid making a breaking change.
82
+ # @deprecated TODO Remove in v7
83
+ def assert_block(message = 'block failed', &block)
84
+ Maze.check.block(message, &block)
85
+ end
86
+
87
+ # Wrapper for Maze.check.true to avoid making a breaking change.
88
+ # @deprecated TODO Remove in v7
89
+ def assert_equal(value, message = nil)
90
+ Maze.check.equal value, message
91
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ module Checks
5
+ # Assertion-backed data verification checks
6
+ class NoopCheck
7
+ def true(_test, _message = nil) end
8
+
9
+ def false(_test, _message = nil) end
10
+
11
+ def nil(_test, _message = nil) end
12
+
13
+ def not_nil(_test, _message = nil) end
14
+
15
+ def match(_pattern, _string, _message = nil) end
16
+
17
+ def equal(_expected, _actual, _message = nil) end
18
+
19
+ def not_equal(_expected, _actual, _message = nil) end
20
+
21
+ def operator(_operand1, _operator, _operand2, _message = nil) end
22
+
23
+ def kind_of(_klass, _object, _message = nil) end
24
+
25
+ def block(_message = 'block failed', &_block) end
26
+
27
+ def include(_collection, _object, _message = nil) end
28
+ alias includes include
29
+
30
+ def not_include(_collection, _object, _message = nil) end
31
+ alias not_includes not_include
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maze
4
+ # Routines for conducting comparisons
5
+ module Compare
6
+ # Provides a way to delivering results of element comparisons to test steps
7
+ class Result
8
+ # @!attribute [r] reasons
9
+ # @return [Array] An array of reasons for a comparison result
10
+ attr_reader :reasons
11
+
12
+ # @!attribute [w] equal
13
+ # @param [Boolean] Indicates if the comparison indicated the elements were equal
14
+ attr_writer :equal
15
+
16
+ # @!attribute [r] keys
17
+ # @return [Array] An array of keys checked
18
+ attr_reader :keys
19
+
20
+ # Creates the Result object
21
+ def initialize
22
+ @equal = true
23
+ @keys = []
24
+ @reasons = []
25
+ end
26
+
27
+ # Indicates if the values compared to produced this result were equal
28
+ #
29
+ # @return [Boolean] Whether the elements were equal
30
+ def equal?
31
+ @equal
32
+ end
33
+
34
+ # Returns the keys traversed in order to compare the end values
35
+ #
36
+ # @return [String] The keypath used in the test
37
+ def keypath
38
+ keys.length > 0 ? keys.reverse.join('.') : '<root>'
39
+ end
40
+
41
+ # Provides a standard assertion of equality, with standardised output
42
+ def assert_equal
43
+ Maze.check.true(@equal, "The compared fields do not match:\n #{result.reasons.join('\n')}")
44
+ end
45
+ end
46
+
47
+ class << self
48
+ # Compares two objects for value equality, traversing to compare each
49
+ # nested object.
50
+ #
51
+ # @param obj1 [Any] The first object to compare
52
+ # @param obj2 [Any] The second object to compare
53
+ # @param result [Result|nil] Optional. Used for comparing recursively
54
+ #
55
+ # @return [Result] The result of comparing the objects
56
+ def value(obj1, obj2, result = nil)
57
+ result ||= Result.new
58
+ return result if obj1 == 'IGNORE'
59
+
60
+ if obj1 == 'NUMBER'
61
+ if obj2.is_a?(Numeric)
62
+ return result
63
+ else
64
+ result.equal = false
65
+ result.reasons << "A Number was expected, '#{obj2.class} received"
66
+ return result
67
+ end
68
+ end
69
+
70
+ unless obj1.class == obj2.class
71
+ result.equal = false
72
+ result.reasons << "Object types differ - expected '#{obj1.class}', received '#{obj2.class}'"
73
+ return result
74
+ end
75
+
76
+ case obj1
77
+ when Array
78
+ array(obj1, obj2, result)
79
+ when Hash
80
+ hash(obj1, obj2, result)
81
+ when String
82
+ string(obj1, obj2, result)
83
+ else
84
+ result.reasons << "#{obj1} is not equal to #{obj2}" unless (result.equal = (obj1 == obj2))
85
+ end
86
+ result
87
+ end
88
+
89
+ # Compares two arrays for value equality, traversing and comparing each element.
90
+ # Results are written to the given Result object.
91
+ #
92
+ # @param array1 [Array] The first array to compare
93
+ # @param array2 [Array] The second array to compare
94
+ # @param result [Result] The Result to store the results
95
+ def array(array1, array2, result)
96
+ unless array1.length == array2.length
97
+ result.equal = false
98
+ result.reasons << "Expected #{array1.length} items in array, received #{array2.length}"
99
+ return
100
+ end
101
+
102
+ array1.each_with_index do |obj1, index|
103
+ value(obj1, array2[index], result)
104
+ unless result.equal?
105
+ result.keys << index.to_s
106
+ break
107
+ end
108
+ end
109
+ end
110
+
111
+ # Compares two hashes for value equality, traversing and comparing each key-value pair.
112
+ # Results are written to the given Result object.
113
+ #
114
+ # @param hash1 [Hash] The first hash to compare
115
+ # @param hash2 [Hash] The second hash to compare
116
+ # @param result [Result] The Result to store the results
117
+ def hash(hash1, hash2, result)
118
+ unless hash1.keys.length == hash2.keys.length
119
+ result.equal = false
120
+ missing = hash1.keys - hash2.keys
121
+ unexpected = hash2.keys - hash1.keys
122
+ result.reasons << "Missing keys from hash: #{missing.join(',')}" unless missing.empty?
123
+ result.reasons << "Unexpected keys in hash: #{unexpected.join(',')}" unless unexpected.empty?
124
+ return
125
+ end
126
+
127
+ hash1.each do |key, value|
128
+ value(value, hash2[key], result)
129
+ unless result.equal?
130
+ result.keys << key
131
+ break
132
+ end
133
+ end
134
+ end
135
+
136
+ # Compares two strings, writing the results to the given Result object.
137
+ #
138
+ # @param template [String] The expected string
139
+ # @param str2 [String] The string to compare
140
+ # @param result [Result] The Result to store the results
141
+ def string(template, str2, result)
142
+ return if template == str2 || regex_match(template, str2)
143
+
144
+ result.equal = false
145
+ result.reasons << "'#{str2}' does not match '#{template}'"
146
+ end
147
+
148
+ # Matches a string against a regex
149
+ #
150
+ # @param template [String] The regex to test with
151
+ # @param value [String] The value to test
152
+ #
153
+ # @return [Boolean] Whether the regex produced a match
154
+ def regex_match(template, value)
155
+ regex = template
156
+ regex = "^#{regex}$" unless regex.start_with?('^') || regex.end_with?('$')
157
+ value =~ /#{regex}/
158
+ end
159
+ end
160
+ end
161
+ end