• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / pdc_describe / 3453062d-fc36-4443-940d-ef7f6c0aac17

09 Sep 2025 06:51PM UTC coverage: 95.463% (-0.05%) from 95.512%
3453062d-fc36-4443-940d-ef7f6c0aac17

push

circleci

web-flow
Allow diacritics in file names (#2158)

8 of 10 new or added lines in 3 files covered. (80.0%)

3535 of 3703 relevant lines covered (95.46%)

396.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.67
/app/models/upload_snapshot.rb
1
# frozen_string_literal: true
2
class UploadSnapshot < ApplicationRecord
2✔
3
  belongs_to :work
2✔
4
  attr_writer :upload
2✔
5

6
  alias_attribute :existing_files, :files
2✔
7

8
  def snapshot_deletions(work_changes, s3_filenames)
2✔
9
    s3_filenames_sorted = s3_filenames.sort
80✔
10
    existing_files.each do |file|
80✔
11
      filename = file["filename"]
78✔
12
      # Use Ruby's Binary Search functionality instead of a plain Ruby Array `.include?`
13
      # to detect missing values in the array because the binary search performs
14
      # much faster when the list of files is large. Notice that the binary search
15
      # requires that the list of files is sorted.
16
      # See https://ruby-doc.org/3.3.6/bsearch_rdoc.html
17
      if s3_filenames_sorted.bsearch { |s3_filename| filename <=> s3_filename }.nil?
184✔
18
        work_changes << { action: "removed", filename:, checksum: file["checksum"] }
46✔
19
      end
20
    end
21
  end
22

23
  def snapshot_modifications(work_changes, s3_files)
2✔
24
    # check for modifications
25
    s3_files.each do |s3_file|
80✔
26
      match = existing_files_sorted.bsearch { |file| s3_file.filename <=> file["filename"] }
232✔
27
      if match.nil?
124✔
28
        work_changes << { action: "added", filename: s3_file.filename, checksum: s3_file.checksum }
88✔
29
      elsif UploadSnapshot.checksum_compare(match["checksum"], s3_file.checksum) == false
36✔
30
        work_changes << { action: "replaced", filename: s3_file.filename, checksum: s3_file.checksum }
6✔
31
      end
32
    end
33
  end
34

35
  def upload
2✔
36
    @upload ||= uploads.find { |s3_file| filenames.include?(s3_file.filename) }
12✔
37
  end
38

39
  def uri
2✔
40
    URI.parse(url)
2✔
41
  end
42

43
  def filenames
2✔
44
    files.map { |file| file["filename"] }
12✔
45
  end
46

47
  def store_files(s3_files)
2✔
48
    self.files = s3_files.map { |file| { "filename" => file.filename, "checksum" => file.checksum } }
182✔
49
  end
50

51
  def self.find_by_filename(work_id:, filename:)
2✔
52
    find_by("work_id = ? AND files @> ?", work_id, JSON.dump([{ filename: }]))
6✔
53
  end
54

55
  class << self
2✔
56
    # Compares two checksums. Accounts for the case in which one of them is
57
    # a plain MD5 value and the other has been encoded with base64.
58
    # See also
59
    #   https://ruby-doc.org/core-2.7.0/Array.html#method-i-pack
60
    #   https://ruby-doc.org/core-2.7.0/String.html#method-i-unpack
61
    def checksum_compare(checksum1, checksum2)
2✔
62
      if checksum1 == checksum2
48✔
63
        true
32✔
64
      elsif checksum1.nil? || checksum2.nil?
16✔
65
        false
4✔
66
      elsif checksum1.length < checksum2.length
12✔
67
        # Decode the first one and then compare
68
        checksum1.unpack("m0").first.unpack("H*").first == checksum2
6✔
69
      else
70
        # Decode the second one and then compare
71
        checksum1 == checksum2.unpack("m0").first.unpack("H*").first
6✔
72
      end
73
    rescue ArgumentError
74
      # One of the values was not properly encoded
75
      false
4✔
76
    rescue NoMethodError
77
      # One of the values was not properly encoded
NEW
78
      false
×
79
    end
80
  end
81

82
  private
2✔
83

84
    def existing_files_sorted
2✔
85
      @existing_files_sorted ||= files.sort_by { |file| file["filename"] }
202✔
86
    end
87

88
    def uploads
2✔
89
      work.uploads
4✔
90
    end
91
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc