danger-dangermattic 1.2.2 → 1.2.3

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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile.lock +95 -57
  5. data/lib/dangermattic/gem_version.rb +1 -1
  6. data/lib/dangermattic/plugins/android_unit_test_checker.rb +7 -4
  7. data/lib/dangermattic/plugins/manifest_pr_checker.rb +13 -1
  8. data/lib/dangermattic/plugins/podfile_checker.rb +2 -0
  9. data/rakelib/console.rake +1 -1
  10. data/rakelib/git_helpers.rake +1 -1
  11. data/spec/android_unit_test_checker_spec.rb +93 -3
  12. data/spec/fixtures/android_unit_test_checker/MixDataPlusNormalClass.kt +14 -0
  13. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/api/ApiResult.kt +69 -0
  14. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/api/WebRecordApi.kt +49 -0
  15. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/domain/drive/UiStates.kt +13 -0
  16. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/main/settings/integrations/connect/AppIntegrationModule.kt +29 -0
  17. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/main/streaks/StreaksViewModel.kt +377 -0
  18. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/mediastorage/MediaStorageConfiguration.kt +31 -0
  19. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/utils/AccountType.kt +15 -0
  20. data/spec/fixtures/android_unit_test_checker/src/main/java/com/dayoneapp/dayone/utils/usecase/SelectPhotoUseCase.kt +76 -0
  21. data/spec/pr_size_checker_spec.rb +14 -14
  22. data/spec/spec_helper.rb +8 -2
  23. data/spec/view_changes_checker_spec.rb +15 -15
  24. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dee5f031f75e2069d6d197e11a2c20be5e8bdd24792e04c36733632886bcbe56
4
- data.tar.gz: 6375edfd326a90f60eb89b073d43896582fe23626624ccf08c148ada39bdacb2
3
+ metadata.gz: 20a5e57d91cc796def3533c72a3a674ea494356982fa78015ccc016ce19b61c9
4
+ data.tar.gz: 376d14c60ba7aadc6107b4a6de9a40dc968a658a0fe326aaad208866bf4583e9
5
5
  SHA512:
6
- metadata.gz: 2c6fdb6234e0f0957b20ab49aa4fc855a546edd73ac26b6d0ecafd8808a2dc5168530e784dc0341044684e0477e77b8d528bf5922753f6286dca47ff8f8d5407
7
- data.tar.gz: 64ec129dac49b60046827c2ca42f91728fc395202cfbe2e4cf8d34773113fd6da4064c02f4f971fab9736f7a2842fd86f9f25d23c6208257c862d55fe7b9c39c
6
+ metadata.gz: 10ed4e5e5772cc7631470fe591c79004a5a237ddaffb6c708204d4823a204f15cc068530c5e8b05bc0f150577037f93bcb675a93ae47eb4c71a5d1b245e658fe
7
+ data.tar.gz: 06c85ea386f290706300db05c3a07439859bda94d025a6dd9bab9068786a2040b247c09c8d1314c31f44c09d07e5aded50434d3092c55aeca1ff9fce2aad78d2
data/.rubocop.yml CHANGED
@@ -1,4 +1,4 @@
1
- require:
1
+ plugins:
2
2
  - rubocop-rake
3
3
  - rubocop-rspec
4
4
 
data/CHANGELOG.md CHANGED
@@ -20,6 +20,12 @@ _None_
20
20
 
21
21
  _None_
22
22
 
23
+ ## 1.2.3
24
+
25
+ ### Bug Fixes
26
+
27
+ - `android_unit_test_checker`: add `annotation` classes as an exception when reporting missing Android unit tests [#101]
28
+
23
29
  ## 1.2.2
24
30
 
25
31
  ### Bug Fixes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- danger-dangermattic (1.2.2)
4
+ danger-dangermattic (1.2.3)
5
5
  danger (~> 9.4)
6
6
  danger-plugin-api (~> 1.0)
7
7
  danger-rubocop (~> 0.13)
@@ -10,10 +10,25 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
+ activesupport (8.0.2)
14
+ base64
15
+ benchmark (>= 0.3)
16
+ bigdecimal
17
+ concurrent-ruby (~> 1.0, >= 1.3.1)
18
+ connection_pool (>= 2.2.5)
19
+ drb
20
+ i18n (>= 1.6, < 2)
21
+ logger (>= 1.4.2)
22
+ minitest (>= 5.1)
23
+ securerandom (>= 0.3)
24
+ tzinfo (~> 2.0, >= 2.0.5)
25
+ uri (>= 0.13.1)
13
26
  addressable (2.8.7)
14
27
  public_suffix (>= 2.0.2, < 7.0)
15
- ast (2.4.2)
16
- base64 (0.2.0)
28
+ ast (2.4.3)
29
+ base64 (0.3.0)
30
+ benchmark (0.4.1)
31
+ bigdecimal (3.2.2)
17
32
  claide (1.1.0)
18
33
  claide-plugins (0.9.2)
19
34
  cork
@@ -21,48 +36,55 @@ GEM
21
36
  open4 (~> 1.3)
22
37
  coderay (1.1.3)
23
38
  colored2 (3.1.2)
39
+ concurrent-ruby (1.3.5)
40
+ connection_pool (2.5.3)
24
41
  cork (0.3.0)
25
42
  colored2 (~> 3.1)
26
- danger (9.5.1)
43
+ danger (9.5.3)
27
44
  base64 (~> 0.2)
28
45
  claide (~> 1.0)
29
46
  claide-plugins (>= 0.9.2)
30
- colored2 (~> 3.1)
47
+ colored2 (>= 3.1, < 5)
31
48
  cork (~> 0.1)
32
49
  faraday (>= 0.9.0, < 3.0)
33
50
  faraday-http-cache (~> 2.0)
34
- git (~> 1.13)
35
- kramdown (~> 2.3)
51
+ git (>= 1.13, < 3.0)
52
+ kramdown (>= 2.5.1, < 3.0)
36
53
  kramdown-parser-gfm (~> 1.0)
37
54
  octokit (>= 4.0)
38
55
  pstore (~> 0.1)
39
- terminal-table (>= 1, < 4)
56
+ terminal-table (>= 1, < 5)
40
57
  danger-plugin-api (1.0.0)
41
58
  danger (> 2.0)
42
59
  danger-rubocop (0.13.0)
43
60
  danger
44
61
  rubocop (~> 1.0)
45
- diff-lcs (1.5.1)
46
- faraday (2.12.0)
47
- faraday-net_http (>= 2.0, < 3.4)
62
+ diff-lcs (1.6.2)
63
+ drb (2.2.3)
64
+ faraday (2.13.4)
65
+ faraday-net_http (>= 2.0, < 3.5)
48
66
  json
49
67
  logger
50
68
  faraday-http-cache (2.5.1)
51
69
  faraday (>= 0.8)
52
- faraday-net_http (3.3.0)
53
- net-http
54
- ffi (1.17.0)
55
- ffi (1.17.0-arm64-darwin)
56
- formatador (1.1.0)
57
- git (1.19.1)
70
+ faraday-net_http (3.4.1)
71
+ net-http (>= 0.5.0)
72
+ ffi (1.17.2)
73
+ ffi (1.17.2-arm64-darwin)
74
+ formatador (1.1.1)
75
+ git (2.3.3)
76
+ activesupport (>= 5.0)
58
77
  addressable (~> 2.8)
78
+ process_executer (~> 1.1)
59
79
  rchardet (~> 1.8)
60
- guard (2.19.0)
80
+ guard (2.19.1)
61
81
  formatador (>= 0.2.4)
62
82
  listen (>= 2.7, < 4.0)
83
+ logger (~> 1.6)
63
84
  lumberjack (>= 1.0.12, < 2.0)
64
85
  nenv (~> 0.1)
65
86
  notiffany (~> 0.0)
87
+ ostruct (~> 0.6)
66
88
  pry (>= 0.13.0)
67
89
  shellany (~> 0.0)
68
90
  thor (>= 0.18.1)
@@ -71,86 +93,102 @@ GEM
71
93
  guard (~> 2.1)
72
94
  guard-compat (~> 1.1)
73
95
  rspec (>= 2.99.0, < 4.0)
74
- json (2.7.5)
75
- kramdown (2.4.0)
76
- rexml
96
+ i18n (1.14.7)
97
+ concurrent-ruby (~> 1.0)
98
+ json (2.13.2)
99
+ kramdown (2.5.1)
100
+ rexml (>= 3.3.9)
77
101
  kramdown-parser-gfm (1.1.0)
78
102
  kramdown (~> 2.0)
79
- language_server-protocol (3.17.0.3)
103
+ language_server-protocol (3.17.0.5)
104
+ lint_roller (1.1.0)
80
105
  listen (3.9.0)
81
106
  rb-fsevent (~> 0.10, >= 0.10.3)
82
107
  rb-inotify (~> 0.9, >= 0.9.10)
83
- logger (1.6.1)
84
- lumberjack (1.2.10)
108
+ logger (1.7.0)
109
+ lumberjack (1.4.0)
85
110
  method_source (1.1.0)
111
+ minitest (5.25.5)
86
112
  nap (1.1.0)
87
113
  nenv (0.3.0)
88
- net-http (0.4.1)
114
+ net-http (0.6.0)
89
115
  uri
90
116
  notiffany (0.1.3)
91
117
  nenv (~> 0.1)
92
118
  shellany (~> 0.0)
93
- octokit (9.2.0)
119
+ octokit (10.0.0)
94
120
  faraday (>= 1, < 3)
95
121
  sawyer (~> 0.9)
96
122
  open4 (1.3.4)
97
- parallel (1.26.3)
98
- parser (3.3.5.1)
123
+ ostruct (0.6.3)
124
+ parallel (1.27.0)
125
+ parser (3.3.9.0)
99
126
  ast (~> 2.4.1)
100
127
  racc
101
- pry (0.14.2)
128
+ prism (1.4.0)
129
+ process_executer (1.3.0)
130
+ pry (0.15.2)
102
131
  coderay (~> 1.1)
103
132
  method_source (~> 1.0)
104
- pstore (0.1.3)
105
- public_suffix (6.0.1)
133
+ pstore (0.2.0)
134
+ public_suffix (6.0.2)
106
135
  racc (1.8.1)
107
136
  rainbow (3.1.1)
108
- rake (13.2.1)
137
+ rake (13.3.0)
109
138
  rb-fsevent (0.11.2)
110
139
  rb-inotify (0.11.1)
111
140
  ffi (~> 1.0)
112
- rchardet (1.8.0)
113
- regexp_parser (2.9.2)
114
- rexml (3.3.9)
115
- rspec (3.13.0)
141
+ rchardet (1.9.0)
142
+ regexp_parser (2.11.0)
143
+ rexml (3.4.2)
144
+ rspec (3.13.1)
116
145
  rspec-core (~> 3.13.0)
117
146
  rspec-expectations (~> 3.13.0)
118
147
  rspec-mocks (~> 3.13.0)
119
- rspec-core (3.13.2)
148
+ rspec-core (3.13.5)
120
149
  rspec-support (~> 3.13.0)
121
- rspec-expectations (3.13.3)
150
+ rspec-expectations (3.13.5)
122
151
  diff-lcs (>= 1.2.0, < 2.0)
123
152
  rspec-support (~> 3.13.0)
124
- rspec-mocks (3.13.2)
153
+ rspec-mocks (3.13.5)
125
154
  diff-lcs (>= 1.2.0, < 2.0)
126
155
  rspec-support (~> 3.13.0)
127
- rspec-support (3.13.1)
128
- rubocop (1.68.0)
156
+ rspec-support (3.13.4)
157
+ rubocop (1.79.2)
129
158
  json (~> 2.3)
130
- language_server-protocol (>= 3.17.0)
159
+ language_server-protocol (~> 3.17.0.2)
160
+ lint_roller (~> 1.1.0)
131
161
  parallel (~> 1.10)
132
162
  parser (>= 3.3.0.2)
133
163
  rainbow (>= 2.2.2, < 4.0)
134
- regexp_parser (>= 2.4, < 3.0)
135
- rubocop-ast (>= 1.32.2, < 2.0)
164
+ regexp_parser (>= 2.9.3, < 3.0)
165
+ rubocop-ast (>= 1.46.0, < 2.0)
136
166
  ruby-progressbar (~> 1.7)
137
- unicode-display_width (>= 2.4.0, < 3.0)
138
- rubocop-ast (1.33.0)
139
- parser (>= 3.3.1.0)
140
- rubocop-rake (0.6.0)
141
- rubocop (~> 1.0)
142
- rubocop-rspec (3.2.0)
143
- rubocop (~> 1.61)
167
+ unicode-display_width (>= 2.4.0, < 4.0)
168
+ rubocop-ast (1.46.0)
169
+ parser (>= 3.3.7.2)
170
+ prism (~> 1.4)
171
+ rubocop-rake (0.7.1)
172
+ lint_roller (~> 1.1)
173
+ rubocop (>= 1.72.1)
174
+ rubocop-rspec (3.6.0)
175
+ lint_roller (~> 1.1)
176
+ rubocop (~> 1.72, >= 1.72.1)
144
177
  ruby-progressbar (1.13.0)
145
178
  sawyer (0.9.2)
146
179
  addressable (>= 2.3.5)
147
180
  faraday (>= 0.17.3, < 3)
181
+ securerandom (0.4.1)
148
182
  shellany (0.0.1)
149
- terminal-table (3.0.2)
150
- unicode-display_width (>= 1.1.1, < 3)
151
- thor (1.3.2)
152
- unicode-display_width (2.6.0)
153
- uri (0.13.1)
183
+ terminal-table (4.0.0)
184
+ unicode-display_width (>= 1.1.1, < 4)
185
+ thor (1.4.0)
186
+ tzinfo (2.0.6)
187
+ concurrent-ruby (~> 1.0)
188
+ unicode-display_width (3.1.4)
189
+ unicode-emoji (~> 4.0, >= 4.0.4)
190
+ unicode-emoji (4.0.4)
191
+ uri (1.0.3)
154
192
  yard (0.9.37)
155
193
 
156
194
  PLATFORMS
@@ -170,4 +208,4 @@ DEPENDENCIES
170
208
  yard
171
209
 
172
210
  BUNDLED WITH
173
- 2.4.13
211
+ 2.6.8
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dangermattic
4
- VERSION = '1.2.2'
4
+ VERSION = '1.2.3'
5
5
  end
@@ -24,14 +24,15 @@ module Danger
24
24
  #
25
25
  class AndroidUnitTestChecker < Plugin
26
26
  ANY_CLASS_DETECTOR = /class\s+([A-Z]\w+)\s*(.*?)\s*{/m
27
- CLASS_MODIFIER_DETECTOR = /((?:\s|public|internal|protected|private|final|abstract|static|data|enum|sealed|value)*)class\s+([A-Z]\w+)\s*(.*?)\s*{/m
27
+ CLASS_MODIFIER_DETECTOR = /((?:\s|public|internal|protected|private|final|abstract|static|data|enum|sealed|value|annotation)*)class\s+([A-Z]\w+)\s*(.*?)\s*({|\n\n)/m
28
28
 
29
29
  CLASS_MODIFIER_EXCEPTIONS = [
30
30
  /\s*data\s*/,
31
31
  /\s*private\s*/,
32
32
  /\s*enum\s*/,
33
33
  /\s*sealed\s*/,
34
- /\s*value\s*/
34
+ /\s*value\s*/,
35
+ /\s*annotation\s*/
35
36
  ].freeze
36
37
 
37
38
  DEFAULT_CLASSES_EXCEPTIONS = [
@@ -95,6 +96,7 @@ module Danger
95
96
  private
96
97
 
97
98
  ClassViolation = Struct.new(:classname, :file)
99
+ private_constant :ClassViolation
98
100
 
99
101
  # @param git_diff [Git::Diff] the git diff object
100
102
  # @param classes_exceptions [Array<String>] Regexes matching class names to exclude from the check.
@@ -151,7 +153,7 @@ module Danger
151
153
  # @return [Array<ClassViolation>] An array of ClassViolation objects representing the violations found.
152
154
  def find_violations(path:, diff_patch:, classes_exceptions:, subclasses_exceptions:)
153
155
  added_lines = git_utils.added_lines(diff_patch: diff_patch)
154
- matches = added_lines.scan(CLASS_MODIFIER_DETECTOR)
156
+ matches = "#{added_lines}\n".scan(CLASS_MODIFIER_DETECTOR) # add a newline to ensure the regex matches the last class in the file
155
157
  matches.reject! do |m|
156
158
  class_match_is_exception?(
157
159
  m,
@@ -180,10 +182,11 @@ module Danger
180
182
  # @param classes_exceptions [Array<String>] Regexes matching class names to exclude from the check.
181
183
  # @param subclasses_exceptions [Array<String>] Regexes matching base class names to exclude from the check
182
184
  #
183
- # @return [void]
185
+ # @return [Boolean]
184
186
  def class_match_is_exception?(match, file, classes_exceptions, subclasses_exceptions)
185
187
  return true if classes_exceptions.any? { |re| match[1] =~ re }
186
188
  return true if CLASS_MODIFIER_EXCEPTIONS.any? { |re| match[0] =~ re }
189
+ return true unless match[3].include?('{') # Ignore classes that don't have a body
187
190
 
188
191
  subclass_regexp = File.extname(file) == '.java' ? /extends\s+([A-Z]\w+)/m : /\s*:\s*([A-Z]\w+)/m
189
192
  subclass = match[2].scan(subclass_regexp)&.last&.last
@@ -29,7 +29,17 @@ module Danger
29
29
  #
30
30
  class ManifestPRChecker < Plugin
31
31
  MESSAGE = '`%s` was changed without updating its corresponding `%s`. %s.'
32
- SWIFT_INSTRUCTION = 'Please resolve the Swift packages as appropriate to your project setup (e.g. in Xcode or by running `swift package resolve`)'
32
+
33
+ # The two new lines at the start are intentional.
34
+ # This will be interpolated in MESSAGE into the final %s.
35
+ # The first new line moves it to a new line, the second adds visual padding.
36
+ SWIFT_INSTRUCTION = <<~INSTRUCTION
37
+
38
+
39
+ If the change includes adding, removing, or editing a dependency please resolve the Swift packages as appropriate to your project setup (e.g. in Xcode or by running `swift package resolve`).
40
+
41
+ If the change to the `Package.swift` did not modify dependencies, ignoring this warning should be safe, but we recommend double checking and running the package resolution just in case.
42
+ INSTRUCTION
33
43
 
34
44
  # Performs all the checks, asserting that changes on `Gemfile`, `Podfile` and `Package.swift` must have corresponding
35
45
  # lock file changes.
@@ -88,6 +98,8 @@ module Danger
88
98
  # Check if the `Package.swift` file was modified without a corresponding `Package.resolved` update,
89
99
  # checking for exact path matches
90
100
  #
101
+ # @param manifest_path [String] The path to the `Package.swift` file.
102
+ # @param manifest_lock_path [String] The path to the `Package.resolved` file.
91
103
  # @param report_type [Symbol] (optional) The type of report for the message. Types: :error, :warning (default), :message.
92
104
  #
93
105
  # @return [void]
@@ -86,7 +86,9 @@ module Danger
86
86
  private
87
87
 
88
88
  COMMIT_REFERENCE_REGEXP = /\(from `\S+`, commit `\S+`\)/
89
+ private_constant :COMMIT_REFERENCE_REGEXP
89
90
  BRANCH_REFERENCE_REGEXP = /\(from `\S+`, branch `\S+`\)/
91
+ private_constant :BRANCH_REFERENCE_REGEXP
90
92
 
91
93
  def check_podfile_does_not_match(
92
94
  regexp:,
data/rakelib/console.rake CHANGED
@@ -38,7 +38,7 @@ module Console
38
38
  answer
39
39
  end
40
40
 
41
- def self.confirm(text)
41
+ def self.confirm?(text)
42
42
  color_puts("#{text} [y/n]?", color_code: GREEN)
43
43
  answer = $stdin.gets.chomp
44
44
  answer.downcase == 'y'
@@ -17,7 +17,7 @@ module GitHelper
17
17
  elsif branch_exists
18
18
  Rake.sh('git', 'checkout', release_branch)
19
19
  else # create it
20
- abort('Aborted, as not run from trunk nor release branch') unless current_branch == 'trunk' || Console.confirm("You are not on 'trunk', nor already on '#{release_branch}'. Do you really want to cut the release branch from #{current_branch}?")
20
+ abort('Aborted, as not run from trunk nor release branch') unless current_branch == 'trunk' || Console.confirm?("You are not on 'trunk', nor already on '#{release_branch}'. Do you really want to cut the release branch from #{current_branch}?")
21
21
 
22
22
  Rake.sh('git', 'checkout', '-b', release_branch)
23
23
  end
@@ -144,6 +144,93 @@ module Danger
144
144
  expect(@dangerfile).to not_report
145
145
  end
146
146
 
147
+ it 'ensures data classes with no {…} body don\'t mess up detection of subsequent classes in the same file' do
148
+ # Ensure the CLASS_MODIFIER_DETECTOR regex doesn't assume class declaration always ends with `{` marking the class body
149
+ # (which would lead the regex to either miss the data class or extend the regex to the next `{`… that potentially belongs to the next class)
150
+ # This is especially important given data classes might not have a body at all
151
+
152
+ mix_data_plus_normal_class_file = 'MixDataPlusNormalClass.kt'
153
+ data_and_normal_class_diff = generate_add_diff_from_fixtures([mix_data_plus_normal_class_file])
154
+
155
+ allow(@dangerfile.git).to receive(:diff).and_return(data_and_normal_class_diff)
156
+
157
+ @plugin.check_missing_tests
158
+
159
+ expect_class_names_match_report(class_names: ['DummyClassMissingTest'], error_report: @dangerfile.status_report[:errors])
160
+ end
161
+
162
+ context 'when detecting classes and class modifiers' do
163
+ let(:added_files) do
164
+ dayone_source_fixtures_subdir = %w[src main java com dayoneapp dayone]
165
+ Dir.glob('**/*.kt', base: fixture_path('android_unit_test_checker', dayone_source_fixtures_subdir))
166
+ .map { |file| File.join(dayone_source_fixtures_subdir, file) }
167
+ end
168
+ let(:diff) { generate_add_diff_from_fixtures(added_files) }
169
+
170
+ # ClassName => Expected to be detected (true) or ignored (false)
171
+ let(:expected_detected_classes) do
172
+ {
173
+ # ApiResult.kt
174
+ 'ApiResult' => false, # `sealed class ApiResult<T>`
175
+ 'Success' => false, # `data class Success<T>`
176
+ 'Empty' => false, # `class Empty<T> : ApiResult<T>()` (but no body)
177
+ 'Failure' => false, # `data class Failure<T>(…)`
178
+ 'FailureType' => false, # `enum class FailureType`
179
+
180
+ # WebRecordApi.kt
181
+ 'CursorTime' => false, # `value class CursorTime`
182
+ 'WebRecordChanges' => false, # `data class WebRecordChanges`
183
+
184
+ # UiStates.kt
185
+ 'LoadKeyUiState' => false, # `sealed class LoadKeyUiState`
186
+
187
+ # AppIntegrationModule.kt
188
+ 'AppIntegrationHandlers' => false, # `annotation class AppIntegrationHandlers`
189
+
190
+ # StreaksViewModel.kt
191
+ 'StreaksViewModel' => true, # `class StreaksViewModel`
192
+ 'Streaks' => false, # `data class Streaks`
193
+ 'JournalOptionsState' => false, # `class JournalOptionsState` (but no body)
194
+ 'StreakWeekDay' => false, # `data class StreakWeekDay`
195
+ 'DayJournaled' => false, # `value class DayJournaled`
196
+ 'StreakJournal' => false, # `data class StreakJournal`
197
+ 'DaysOfWeekList' => false, # `private class DaysOfWeekList`
198
+ 'PreviousDays' => false, # `class PreviousDays` (but no body)
199
+
200
+ # MediaStorageConfiguration.kt
201
+ 'CompressQuality' => false, # `value class CompressQuality`
202
+ 'MediaStorageConfiguration' => false, # `class MediaStorageConfiguration` (but no body)
203
+ 'ThumbnailsConfiguration' => false, # `class ThumbnailsConfiguration` (but no body)
204
+
205
+ # AccountType.kt
206
+ 'AccountType' => false, # `enum class AccountType`
207
+
208
+ # SelectPhotoUseCase.kt
209
+ 'SelectPhotoUseCase' => true, # `class SelectPhotoUseCase`
210
+ 'GetMultipleImages' => false, # `private class GetMultipleImages`
211
+ 'GetSingleImage' => false # `private class GetSingleImage`
212
+ }
213
+ end
214
+
215
+ before do
216
+ allow(@dangerfile.git).to receive(:diff).and_return(diff)
217
+ end
218
+
219
+ it 'reports only classes that don\'t have a modifier that is part of modifier exceptions' do
220
+ @plugin.check_missing_tests
221
+ expected_violating_classes = expected_detected_classes.filter_map { |k, v| k if v } # only keys whose value is true
222
+ expect_class_names_match_report(class_names: expected_violating_classes, error_report: @dangerfile.status_report[:errors])
223
+ end
224
+
225
+ it 'validates that the RegEx matches all classes from source code' do
226
+ # Mock detection of exceptions in order to make `check_missing_tests` report all classes regardless of modifiers
227
+ # This allows us to validate that our RegEx matches all classes from the source code in the first place
228
+ allow(@plugin).to receive(:class_match_is_exception?).and_return(false)
229
+ @plugin.check_missing_tests
230
+ expect_class_names_match_report(class_names: expected_detected_classes.keys, error_report: @dangerfile.status_report[:errors])
231
+ end
232
+ end
233
+
147
234
  it 'does not report that a PR with the tests bypass label is missing tests' do
148
235
  added_files = %w[
149
236
  Abc.java
@@ -301,7 +388,7 @@ module Danger
301
388
 
302
389
  def generate_add_diff_from_fixtures(paths)
303
390
  paths.map do |path|
304
- content = fixture(File.join('android_unit_test_checker', path))
391
+ content = fixture('android_unit_test_checker', path)
305
392
  diff_str = generate_add_diff(file_path: path, content: content)
306
393
 
307
394
  GitDiffStruct.new('new', path, diff_str)
@@ -310,7 +397,7 @@ module Danger
310
397
 
311
398
  def generate_delete_diff_from_fixtures(paths)
312
399
  paths.map do |path|
313
- content = fixture(File.join('android_unit_test_checker', path))
400
+ content = fixture('android_unit_test_checker', path)
314
401
  diff_str = generate_delete_diff(file_path: path, content: content)
315
402
 
316
403
  GitDiffStruct.new('deleted', path, diff_str)
@@ -348,7 +435,10 @@ module Danger
348
435
  end
349
436
 
350
437
  def expect_class_names_match_report(class_names:, error_report:)
351
- expect(class_names.length).to eq(error_report.length)
438
+ if error_report.length != class_names.length
439
+ reported_class_names = error_report.map { |e| e.match(/class `(.*?)`/)[1] }
440
+ expect(reported_class_names).to eq(class_names)
441
+ end
352
442
  class_names.zip(error_report).each do |cls, error|
353
443
  expect(error).to include "Please add tests for class `#{cls}`"
354
444
  end
@@ -0,0 +1,14 @@
1
+ import javax.inject.Inject
2
+ import javax.inject.Singleton
3
+
4
+ internal data class DummyDataClassNotNeedingTests(
5
+ val title: String,
6
+ val id: String
7
+ )
8
+
9
+ @Singleton
10
+ internal class DummyClassMissingTest @Inject constructor(
11
+ private val name: String,
12
+ ) : ParentClass {
13
+ private val loggingTag = 'mylogging'
14
+ }
@@ -0,0 +1,69 @@
1
+ package com.dayoneapp.dayone.api
2
+
3
+ import com.dayoneapp.dayone.api.ApiResult.Failure
4
+ import com.dayoneapp.dayone.api.ApiResult.FailureType.GENERIC
5
+ import com.dayoneapp.dayone.api.ApiResult.FailureType.SERVER_ERROR
6
+ import com.dayoneapp.dayone.api.ApiResult.FailureType.TIMEOUT
7
+ import com.dayoneapp.dayone.api.ApiResult.FailureType.UNAUTHORIZED
8
+ import com.dayoneapp.syncservice.NetworkErrorType
9
+ import com.google.api.client.http.HttpStatusCodes
10
+ import retrofit2.Response
11
+ import java.io.IOException
12
+
13
+ sealed class ApiResult<T> {
14
+ data class Success<T>(
15
+ val data: T,
16
+ ) : ApiResult<T>()
17
+
18
+ class Empty<T> : ApiResult<T>()
19
+
20
+ data class Failure<T>(
21
+ val type: FailureType,
22
+ val errorCode: Int? = null,
23
+ val errorMessage: String? = null,
24
+ ) : ApiResult<T>()
25
+
26
+ enum class FailureType {
27
+ SERVER_ERROR,
28
+ UNAUTHORIZED,
29
+ TIMEOUT,
30
+ GENERIC,
31
+ NOT_CONNECTED,
32
+ ;
33
+
34
+ companion object {
35
+ fun fromNetworkErrorType(networkErrorType: NetworkErrorType): FailureType =
36
+ when (networkErrorType) {
37
+ NetworkErrorType.SERVER_ERROR -> SERVER_ERROR
38
+ NetworkErrorType.UNAUTHORIZED -> UNAUTHORIZED
39
+ NetworkErrorType.TIMEOUT -> TIMEOUT
40
+ NetworkErrorType.GENERIC -> GENERIC
41
+ else -> {
42
+ GENERIC
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ suspend fun <T> apiCall(apiCall: suspend () -> Response<T>): ApiResult<T> =
50
+ try {
51
+ with(apiCall()) {
52
+ if (this.isSuccessful) {
53
+ this.body()?.let {
54
+ ApiResult.Success(it)
55
+ } ?: ApiResult.Empty()
56
+ } else {
57
+ val type =
58
+ when (this.code()) {
59
+ HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, HttpStatusCodes.STATUS_CODE_FORBIDDEN -> UNAUTHORIZED
60
+ HttpStatusCodes.STATUS_CODE_SERVER_ERROR -> SERVER_ERROR
61
+ else -> GENERIC
62
+ }
63
+ Failure(type, this.code(), this.message())
64
+ }
65
+ }
66
+ } catch (e: IOException) {
67
+ Failure(TIMEOUT)
68
+ }
69
+
@@ -0,0 +1,49 @@
1
+ package com.dayoneapp.dayone.api
2
+
3
+ import com.dayoneapp.dayone.domain.sync.WebRecordRemote
4
+ import com.google.gson.annotations.SerializedName
5
+ import retrofit2.Response
6
+ import retrofit2.http.*
7
+
8
+ @JvmInline
9
+ value class CursorTime(
10
+ val time: String,
11
+ )
12
+
13
+ val ZeroCursorTime = CursorTime("0")
14
+
15
+ data class WebRecordChanges(
16
+ @SerializedName("changes")
17
+ val changes: List<WebRecordRemote>,
18
+ @SerializedName("cursor")
19
+ val cursor: String,
20
+ )
21
+
22
+ interface WebRecordApi {
23
+ @POST("$SYNC/named/{name}")
24
+ suspend fun createRecord(
25
+ @Path("name") name: String,
26
+ @Body record: WebRecordRemote,
27
+ ): Response<WebRecordRemote>
28
+
29
+ @PUT("$SYNC/{syncId}")
30
+ suspend fun updateRecord(
31
+ @Path("syncId") syncId: String,
32
+ @Body record: WebRecordRemote,
33
+ ): Response<WebRecordRemote>
34
+
35
+ @GET("$SYNC/named/{name}")
36
+ suspend fun fetchRecord(
37
+ @Path("name") name: String,
38
+ ): Response<WebRecordRemote>
39
+
40
+ @GET("$SYNC/changes/{kind}")
41
+ suspend fun fetchRecordChanges(
42
+ @Path("kind") kind: String,
43
+ @Query("cursor") cursor: CursorTime,
44
+ ): Response<WebRecordChanges>
45
+
46
+ companion object {
47
+ const val SYNC = "/api/v4/sync"
48
+ }
49
+ }
@@ -0,0 +1,13 @@
1
+ package com.dayoneapp.dayone.domain.drive
2
+
3
+ sealed class LoadKeyUiState(
4
+ val buttonEnabled: Boolean,
5
+ ) {
6
+ object Init : LoadKeyUiState(buttonEnabled = true)
7
+
8
+ object Loading : LoadKeyUiState(buttonEnabled = false)
9
+
10
+ object KeyLoaded : LoadKeyUiState(buttonEnabled = false)
11
+
12
+ object KeyNotFound : LoadKeyUiState(buttonEnabled = true)
13
+ }