Skip to content

Commit 886fa7a

Browse files
Addition of tests. Large commit, one message won't do it justice.
1 parent 10eedd6 commit 886fa7a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2340
-19
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@
2525
*.csv
2626
*-shm
2727
*-wal
28+
*-wal2
2829

2930
## Stuff I shouldn't index
3031
passwords.txt
32+
spec/data/itunes_backup
33+
spec/data/physical_backup
34+
spec/data/mac_backup
35+
spec/data/mac_backup_old
3136

3237
## Documentation cache and generated files:
3338
/.yardoc/

.travis.yml

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,7 @@ os:
55
- osx
66

77
rvm:
8-
- "2.3.0"
9-
- "2.3.1"
10-
- "2.4.3"
11-
- "2.5.1"
12-
- "2.6.5"
13-
- "2.7.1"
14-
15-
jobs:
16-
exclude:
17-
- os: osx
18-
rvm: 2.3.0
19-
- os: osx
20-
rvm: 2.3.1
8+
- "3.0"
9+
- "3.1"
10+
- "3.2"
11+
- "3.3"

FolderStructure.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,20 @@ apple_cloud_notes_parser
3131
| |-NoteStore.sqlite: If run on a modern version, this copy of the target file will include plaintext versions of the Notes
3232
| |-notes.sqlite: If run on a legacy version, this copy is just a copy for ease of use
3333
|
34+
|-spec
35+
| |
36+
| |-backup: Test specs related to Backup classes.
37+
| |-base_classes: Test specs related to foundational classes like AppleNote.
38+
| |-data: Folder container test data. See [this file](spec/data/README.md) for the folder structure if you want to add data.
39+
| |-embedded_objects: Test specs related to EmbeddedObjects. This needs the most work.
40+
| |-integration: Test specs related to the full program running.
41+
| |-output: Test specs related to how output should appear. WARNING, this may change as things are stablized.
42+
| |-spec.rb: The base RSpec file.
43+
| |-utilities: Test specs related to utility classes like AppleDecrypter.
44+
|
3445
|-.gitignore
3546
|-.travis.yml
36-
|-Dockerfile
47+
|-Dockerfile: The Dockerfile for Github's Docker registry
3748
|-Gemfile
3849
|-LICENSE
3950
|-README.md

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This program will:
2222
7. ... displaying tables as actual tables and ripping the embedded images from the backup and putting them into a folder with the other output files for review
2323
8. ... identifying the CloudKit participants involved in any shared items.
2424
9. ... producing well-structured JSON for automated backups
25+
10. ... actually run tests against its output after 5 years of YOLO.
2526

2627
## Usage
2728

@@ -243,6 +244,18 @@ On each OS, you will want to:
243244
5. Use bundler to install the required gems.
244245
6. Run the program (see Usage section)!
245246
247+
## Tests
248+
249+
As of August 2024, tests have been added using [RSpec](https://rspec.info/).
250+
This test suite is not finished and has been in progress for a while, but in order to maintain consistent output with a few key additions, some tests are needed sooner than all tests.
251+
Because a lot of the test data is inherently sensitive, coming from large Apple Notes backups that contain PII, the tests have been structured to [accept symlinks](spec/data/README.md) and skip tests that require data which is not shareable.
252+
While this means that not everyone can benefit from the full test suite, I felt it better to have some data available for tests for PRs rather than keep all of them private.
253+
To the extent that data can be extracted and committed into the repo, outside of full backups, that is the preference.
254+
255+
By default, running `rake test` will skip any tests that are fairly "expensive", primarily in terms of disk IO.
256+
If you want to run just the expensive tests, use `rake test_expensive`.
257+
If you want to run everything, use `rake test_all`.
258+
246259
## FAQ
247260
248261
#### Where can I find (pick file X) to edit this?

Rakefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'rspec/core'
2+
13
# By default, execute "run"
24
task default: %w[run]
35

@@ -16,3 +18,15 @@ end
1618
task :clean do
1719
FileUtils.rm_rf('output')
1820
end
21+
22+
task :test do
23+
RSpec::Core::Runner.run(["spec/spec.rb", "--tag", "~expensive"])
24+
end
25+
26+
task :test_expensive do
27+
RSpec::Core::Runner.run(["spec/spec.rb", "--tag", "expensive"])
28+
end
29+
30+
task :test_all do
31+
RSpec::Core::Runner.run(["spec/spec.rb", "--tag", "~missing_data"])
32+
end

lib/ProtoPatches.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,17 @@ def same_style?(other_attribute_run)
6868

6969
no_attachment_info = !attachment_info # We don't want to get so greedy with attachments
7070

71-
return (same_paragraph and same_font and same_font_weight and same_underlined and same_strikethrough and same_superscript and same_link and same_color and same_attachment_info and no_attachment_info and same_block_quote)
71+
return (same_paragraph and
72+
same_font and
73+
same_font_weight and
74+
same_underlined and
75+
same_strikethrough and
76+
same_superscript and
77+
same_link and
78+
same_color and
79+
same_attachment_info and
80+
no_attachment_info and
81+
same_block_quote)
7282
end
7383

7484
##
@@ -170,7 +180,9 @@ def is_any_list?
170180
# it has to recursively check the previous AttributeRuns.
171181
def total_indent
172182

173-
to_return = 0
183+
return @indent if @indent
184+
185+
@indent = 0
174186

175187
# Determine what this AttributeRun's indent amount is on its own
176188
my_indent = 0
@@ -180,13 +192,13 @@ def total_indent
180192

181193
# If there is no previous AttributeRun, the answer is just this AttributeRun's indent amount
182194
if !previous_run
183-
to_return = my_indent
195+
@indent = my_indent
184196
# If there is something previous, add our indent to its total indent
185197
else
186-
to_return = my_indent + previous_run.total_indent
198+
@indent = my_indent + previous_run.total_indent
187199
end
188200

189-
return to_return
201+
return @indent
190202
end
191203

192204
def open_html_tag(tag_name, attributes = {})

spec/backup/apple_backup.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
require_relative '../../lib/AppleBackup.rb'
2+
3+
describe AppleBackup, :expensive => true do
4+
before(:context) do
5+
TEST_OUTPUT_DIR.mkpath
6+
end
7+
after(:context) do
8+
TEST_OUTPUT_DIR.rmtree
9+
end
10+
11+
let(:backup) { AppleBackup.new(TEST_DATA_DIR, 0, TEST_OUTPUT_DIR) }
12+
13+
context "validations" do
14+
it "raises an error rather than failing validation" do
15+
expect{backup.valid?}.to raise_error("AppleBackup cannot stand on its own")
16+
end
17+
18+
end
19+
20+
context "files" do
21+
it "raises an error since it has no real file path" do
22+
expect{backup.get_real_file_path("test.tmp")}.to raise_error("Cannot return file_path for AppleBackup")
23+
end
24+
end
25+
end

spec/backup/apple_backup_file.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
require_relative '../../lib/AppleBackupFile.rb'
2+
3+
describe AppleBackupFile, :expensive => true do
4+
before(:context) do
5+
TEST_OUTPUT_DIR.mkpath
6+
end
7+
after(:context) do
8+
TEST_OUTPUT_DIR.rmtree
9+
end
10+
11+
let(:valid_backup) { AppleBackupFile.new(TEST_FORMATTING_FILE, TEST_OUTPUT_DIR) }
12+
13+
context "validations" do
14+
it "validates a NoteStore.sqlite file", :missing_data => !TEST_FORMATTING_FILE_EXIST do
15+
expect(valid_backup.valid?).to be true
16+
end
17+
18+
it "fails to validate a non-NoteStore sqlite file", :missing_data => !TEST_FALSE_SQLITE_FILE_EXIST do
19+
backup = AppleBackupFile.new(TEST_FALSE_SQLITE_FILE, TEST_OUTPUT_DIR)
20+
expect(backup.valid?).to be false
21+
end
22+
23+
it "fails to validate a non-sqlite file", :missing_data => !TEST_README_FILE_EXIST do
24+
backup = AppleBackupFile.new(TEST_README_FILE, TEST_OUTPUT_DIR)
25+
expect(backup.valid?).to be false
26+
end
27+
28+
it "fails to validate an itunes backup folder", :missing_data => !TEST_ITUNES_DIR_EXIST do
29+
backup = AppleBackupFile.new(TEST_ITUNES_DIR, TEST_OUTPUT_DIR)
30+
expect(backup.valid?).to be false
31+
end
32+
33+
it "fails to validate a physical backup folder", :missing_data => !TEST_PHYSICAL_DIR_EXIST do
34+
backup = AppleBackupFile.new(TEST_PHYSICAL_DIR, TEST_OUTPUT_DIR)
35+
expect(backup.valid?).to be false
36+
end
37+
38+
it "fails to validate a mac backup folder", :missing_data => !TEST_MAC_DIR_EXIST do
39+
backup = AppleBackupFile.new(TEST_MAC_DIR, TEST_OUTPUT_DIR)
40+
expect(backup.valid?).to be false
41+
end
42+
end
43+
44+
context "versions" do
45+
46+
it "correctly identifies all major versions" do
47+
# To do: acquire iOS 11 sample for here
48+
TEST_FILE_VERSIONS.each_pair do |version, version_file|
49+
backup = AppleBackupFile.new(version_file, TEST_OUTPUT_DIR)
50+
expect(backup.note_stores[0].version.version_number).to be version
51+
end
52+
end
53+
end
54+
55+
context "files", :missing_data => !TEST_FORMATTING_FILE_EXIST do
56+
it "does not try to assert where a file is" do
57+
backup = AppleBackupFile.new(TEST_FORMATTING_FILE, TEST_OUTPUT_DIR)
58+
expect(valid_backup.get_real_file_path("NoteStore.sqlite")).to be nil
59+
end
60+
end
61+
62+
context "note stores", :missing_data => !TEST_FORMATTING_FILE_EXIST do
63+
it "knows how to find just a modern note store" do
64+
expect(valid_backup.note_stores.length).to be 1
65+
end
66+
end
67+
end

spec/backup/apple_backup_hashed.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
require_relative '../../lib/AppleBackupHashed.rb'
2+
3+
describe AppleBackupHashed, :expensive => true do
4+
before(:context) do
5+
TEST_OUTPUT_DIR.mkpath
6+
end
7+
after(:context) do
8+
TEST_OUTPUT_DIR.rmtree
9+
end
10+
11+
let(:valid_backup) { AppleBackupHashed.new(TEST_ITUNES_DIR, TEST_OUTPUT_DIR) }
12+
13+
context "validations" do
14+
it "validates an itunes backup folder", :missing_data => !TEST_ITUNES_DIR_EXIST do
15+
expect(valid_backup.valid?).to be true
16+
end
17+
18+
it "fails to validate a physical backup folder", :missing_data => !TEST_PHYSICAL_DIR_EXIST do
19+
backup = AppleBackupHashed.new(TEST_PHYSICAL_DIR, TEST_OUTPUT_DIR)
20+
expect(backup.valid?).to be false
21+
end
22+
23+
it "fails to validate a mac backup folder", :missing_data => !TEST_MAC_DIR_EXIST do
24+
backup = AppleBackupHashed.new(TEST_MAC_DIR, TEST_OUTPUT_DIR)
25+
expect(backup.valid?).to be false
26+
end
27+
28+
it "fails to validate a valid NoteStore.sqlite file", :missing_data => !TEST_FORMATTING_FILE_EXIST do
29+
backup = AppleBackupHashed.new(TEST_FORMATTING_FILE, TEST_OUTPUT_DIR)
30+
expect(backup.valid?).to be false
31+
end
32+
end
33+
34+
context "files", :missing_data => !TEST_ITUNES_DIR_EXIST do
35+
it "knows how to find an appropriate file" do
36+
expect(valid_backup.get_real_file_path("NoteStore.sqlite").to_s).to match(/spec\/data\/itunes_backup\/4f\/4f98687d8ab0d6d1a371110e6b7300f6e465bef2/)
37+
end
38+
end
39+
40+
context "note stores", :missing_data => !TEST_ITUNES_DIR_EXIST do
41+
it "knows how to find both legacy and modern note stores" do
42+
expect(valid_backup.note_stores.length).to be 2
43+
end
44+
end
45+
end

spec/backup/apple_backup_mac.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
require_relative '../../lib/AppleBackupMac.rb'
2+
3+
describe AppleBackupMac, :expensive => true do
4+
before(:context) do
5+
TEST_OUTPUT_DIR.mkpath
6+
end
7+
after(:context) do
8+
TEST_OUTPUT_DIR.rmtree
9+
end
10+
11+
let(:valid_backup) { AppleBackupMac.new(TEST_MAC_DIR, TEST_OUTPUT_DIR) }
12+
13+
context "validations" do
14+
it "validates a mac backup folder", :missing_data => !TEST_MAC_DIR_EXIST do
15+
expect(valid_backup.valid?).to be true
16+
end
17+
18+
it "fails to validate an itunes backup folder", :missing_data => !TEST_ITUNES_DIR_EXIST do
19+
backup = AppleBackupMac.new(TEST_ITUNES_DIR, TEST_OUTPUT_DIR)
20+
expect(backup.valid?).to be false
21+
end
22+
23+
it "fails to validate a physical backup folder", :missing_data => !TEST_PHYSICAL_DIR_EXIST do
24+
backup = AppleBackupMac.new(TEST_PHYSICAL_DIR, TEST_OUTPUT_DIR)
25+
expect(backup.valid?).to be false
26+
end
27+
28+
it "fails to validate a valid NoteStore.sqlite file", :missing_data => !TEST_FORMATTING_FILE_EXIST do
29+
backup = AppleBackupMac.new(TEST_FORMATTING_FILE, TEST_OUTPUT_DIR)
30+
expect(backup.valid?).to be false
31+
end
32+
end
33+
34+
context "files", :missing_data => !TEST_MAC_DIR_EXIST do
35+
it "knows how to find an appropriate file" do
36+
expect(valid_backup.get_real_file_path("NoteStore.sqlite").to_s).to match(/spec\/data\/mac_backup\/NoteStore.sqlite/)
37+
end
38+
end
39+
40+
context "note stores", :missing_data => !TEST_MAC_DIR_EXIST do
41+
it "knows how to find just a modern note store" do
42+
expect(valid_backup.note_stores.length).to be 1
43+
end
44+
end
45+
end

0 commit comments

Comments
 (0)