xcunique 0.0.1

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +4 -0
  4. data/Guardfile +22 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +73 -0
  7. data/Rakefile +11 -0
  8. data/bin/xcunique +5 -0
  9. data/lib/json2plist/json2plist +21 -0
  10. data/lib/xcunique.rb +23 -0
  11. data/lib/xcunique/cli.rb +40 -0
  12. data/lib/xcunique/hash_ext.rb +25 -0
  13. data/lib/xcunique/helpers.rb +26 -0
  14. data/lib/xcunique/options.rb +68 -0
  15. data/lib/xcunique/parser.rb +54 -0
  16. data/lib/xcunique/sorter.rb +51 -0
  17. data/lib/xcunique/uniquifier.rb +36 -0
  18. data/lib/xcunique/version.rb +3 -0
  19. data/spec/fixtures/TestProject.json +548 -0
  20. data/spec/fixtures/TestProject/TestProject.xcodeproj/project.pbxproj +510 -0
  21. data/spec/fixtures/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  22. data/spec/fixtures/TestProject/TestProject.xcodeproj/project.xcworkspace/xcuserdata/paul.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  23. data/spec/fixtures/TestProject/TestProject.xcodeproj/xcuserdata/paul.xcuserdatad/xcschemes/TestProject.xcscheme +111 -0
  24. data/spec/fixtures/TestProject/TestProject.xcodeproj/xcuserdata/paul.xcuserdatad/xcschemes/xcschememanagement.plist +47 -0
  25. data/spec/fixtures/TestProject/TestProject/AppDelegate.swift +46 -0
  26. data/spec/fixtures/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  27. data/spec/fixtures/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard +27 -0
  28. data/spec/fixtures/TestProject/TestProject/Base.lproj/Main.storyboard +26 -0
  29. data/spec/fixtures/TestProject/TestProject/Info.plist +47 -0
  30. data/spec/fixtures/TestProject/TestProject/ViewController.swift +25 -0
  31. data/spec/fixtures/TestProject/TestProjectTests/Info.plist +24 -0
  32. data/spec/fixtures/TestProject/TestProjectTests/TestProjectTests.swift +36 -0
  33. data/spec/fixtures/TestProject/TestProjectUITests/Info.plist +24 -0
  34. data/spec/fixtures/TestProject/TestProjectUITests/TestProjectUITests.swift +36 -0
  35. data/spec/spec_helper.rb +4 -0
  36. data/spec/xcunique/hash_ext_spec.rb +36 -0
  37. data/spec/xcunique/helpers_spec.rb +58 -0
  38. data/spec/xcunique/parser_spec.rb +214 -0
  39. data/spec/xcunique/sorter_spec.rb +116 -0
  40. data/xcunique.gemspec +26 -0
  41. metadata +178 -0
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>en</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>BNDL</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleSignature</key>
20
+ <string>????</string>
21
+ <key>CFBundleVersion</key>
22
+ <string>1</string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,36 @@
1
+ //
2
+ // TestProjectUITests.swift
3
+ // TestProjectUITests
4
+ //
5
+ // Created by Paul Samuels on 18/12/2015.
6
+ // Copyright © 2015 Paul Samuels. All rights reserved.
7
+ //
8
+
9
+ import XCTest
10
+
11
+ class TestProjectUITests: XCTestCase {
12
+
13
+ override func setUp() {
14
+ super.setUp()
15
+
16
+ // Put setup code here. This method is called before the invocation of each test method in the class.
17
+
18
+ // In UI tests it is usually best to stop immediately when a failure occurs.
19
+ continueAfterFailure = false
20
+ // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21
+ XCUIApplication().launch()
22
+
23
+ // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24
+ }
25
+
26
+ override func tearDown() {
27
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
28
+ super.tearDown()
29
+ }
30
+
31
+ func testExample() {
32
+ // Use recording to get started writing UI tests.
33
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
34
+ }
35
+
36
+ }
@@ -0,0 +1,4 @@
1
+ require 'xcunique'
2
+
3
+ require 'minitest/spec'
4
+ require 'minitest/autorun'
@@ -0,0 +1,36 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Hash do
4
+
5
+ it 'performs a deep duplicate of simple types' do
6
+ input = {
7
+ "array" => [ 1, 2, 3 ],
8
+ "string" => 'value'
9
+ }
10
+
11
+ result = input.deep_dup
12
+
13
+ assert_equal input, result
14
+ refute_equal input.object_id, result.object_id
15
+ refute_equal input['array'].object_id, result['array'].object_id
16
+ end
17
+
18
+ it 'substitutes objects that match in the substitutes hash' do
19
+ input = {
20
+ 'aaaa' => [ 1, 2, 3 ],
21
+ 'bbbb' => 'cccc',
22
+ 'dddd' => 'eeee'
23
+ }
24
+
25
+ expected = {
26
+ 'AAAA' => [ 1, 2, 3 ],
27
+ 'BBBB' => 'CCCC',
28
+ 'dddd' => 'eeee'
29
+ }
30
+
31
+ result = input.deep_dup(substitutions: { 'aaaa' => 'AAAA', 'bbbb' => 'BBBB', 'cccc' => 'CCCC' })
32
+
33
+ assert_equal expected, result
34
+ end
35
+
36
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Xcunique::Helpers do
4
+
5
+ it "returns an empty string if no name, path or fileRef are found" do
6
+ objects = {
7
+ 'aaaa' => {}
8
+ }
9
+
10
+ assert_equal '', Xcunique::Helpers.resolve_attributes('aaaa', objects)
11
+ end
12
+
13
+ it 'returns the name if found on the object' do
14
+ objects = {
15
+ 'aaaa' => {
16
+ 'name' => 'Test'
17
+ }
18
+ }
19
+
20
+ assert_equal "(name: 'Test')", Xcunique::Helpers.resolve_attributes('aaaa', objects)
21
+ end
22
+
23
+ it 'returns the path if found on the object' do
24
+ objects = {
25
+ 'aaaa' => {
26
+ 'path' => 'Test'
27
+ }
28
+ }
29
+
30
+ assert_equal "(path: 'Test')", Xcunique::Helpers.resolve_attributes('aaaa', objects)
31
+ end
32
+
33
+ it 'returns the name and path if found on the object' do
34
+ objects = {
35
+ 'aaaa' => {
36
+ 'name' => 'Test',
37
+ 'path' => 'Test'
38
+ }
39
+ }
40
+
41
+ assert_equal "(name: 'Test', path: 'Test')", Xcunique::Helpers.resolve_attributes('aaaa', objects)
42
+ end
43
+
44
+ it 'resolves the fileRef if there is one' do
45
+ objects = {
46
+ 'aaaa' => {
47
+ 'fileRef' => 'bbbb'
48
+ },
49
+ 'bbbb' => {
50
+ 'name' => 'Test',
51
+ 'path' => 'Test'
52
+ }
53
+ }
54
+
55
+ assert_equal "(name: 'Test', path: 'Test')", Xcunique::Helpers.resolve_attributes('aaaa', objects)
56
+ end
57
+
58
+ end
@@ -0,0 +1,214 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Xcunique::Parser do
4
+
5
+ before do
6
+ @project = JSON.load(File.open(File.expand_path('../fixtures/TestProject.json', __dir__)))
7
+ @parser = Xcunique::Parser.new(@project)
8
+ end
9
+
10
+ let(:root_uuid) { @project['rootObject'] }
11
+ let(:main_group) { @project['objects'][root_uuid]['mainGroup'] }
12
+
13
+ it 'correctly parses files and groups' do
14
+
15
+ @parser.parse object: main_group
16
+
17
+ result = @parser.visited
18
+
19
+ expectations = {
20
+
21
+ # ├── Project
22
+ "/PBXGroup" => 'DACE56891C24A14C00E6ABB0',
23
+
24
+ # ├── TestProject
25
+ #    ├── Products
26
+ #    ├── TestProject
27
+ #    ├── TestProjectTests
28
+ #    ├── TestProjectUITests
29
+ "/PBXGroup/PBXGroup(name: 'Products')" => 'DACE56931C24A14D00E6ABB0',
30
+ "/PBXGroup/PBXGroup(path: 'TestProject')" => 'DACE56941C24A14D00E6ABB0',
31
+ "/PBXGroup/PBXGroup(path: 'TestProjectTests')" => 'DACE56A91C24A14D00E6ABB0',
32
+ "/PBXGroup/PBXGroup(path: 'TestProjectUITests')" => 'DACE56B41C24A14D00E6ABB0',
33
+
34
+ # ├── TestProject
35
+ # │   ├── AppDelegate.swift
36
+ # │   ├── Assets.xcassets
37
+ # │   ├── Base.lproj
38
+ # │   │   ├── LaunchScreen.storyboard
39
+ # │   │   └── Main.storyboard
40
+ # │   ├── Info.plist
41
+ # │   └── ViewController.swift
42
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXFileReference(path: 'AppDelegate.swift')" => 'DACE56951C24A14D00E6ABB0',
43
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXFileReference(path: 'Assets.xcassets')" => 'DACE569C1C24A14D00E6ABB0',
44
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXVariantGroup(name: 'LaunchScreen.storyboard')" => 'DACE569E1C24A14D00E6ABB0',
45
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXVariantGroup(name: 'LaunchScreen.storyboard')/PBXFileReference(name: 'Base', path: 'Base.lproj/LaunchScreen.storyboard')" => 'DACE569F1C24A14D00E6ABB0',
46
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXVariantGroup(name: 'Main.storyboard')" => 'DACE56991C24A14D00E6ABB0',
47
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXVariantGroup(name: 'Main.storyboard')/PBXFileReference(name: 'Base', path: 'Base.lproj/Main.storyboard')" => 'DACE569A1C24A14D00E6ABB0',
48
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXFileReference(path: 'Info.plist')" => 'DACE56A11C24A14D00E6ABB0',
49
+ "/PBXGroup/PBXGroup(path: 'TestProject')/PBXFileReference(path: 'ViewController.swift')" => 'DACE56971C24A14D00E6ABB0',
50
+
51
+ # ├── TestProject
52
+ #    ├── TestProjectTests
53
+ #    │   ├── Info.plist
54
+ #    │   └── TestProjectTests.swift
55
+ "/PBXGroup/PBXGroup(path: 'TestProjectTests')/PBXFileReference(path: 'Info.plist')" => 'DACE56AC1C24A14D00E6ABB0',
56
+ "/PBXGroup/PBXGroup(path: 'TestProjectTests')/PBXFileReference(path: 'TestProjectTests.swift')" => 'DACE56AA1C24A14D00E6ABB0',
57
+
58
+ # ├── TestProject
59
+ #    └── TestProjectUITests
60
+ #       ├── Info.plist
61
+ #       └── TestProjectUITests.swift
62
+ "/PBXGroup/PBXGroup(path: 'TestProjectUITests')/PBXFileReference(path: 'Info.plist')" => 'DACE56B71C24A14D00E6ABB0',
63
+ "/PBXGroup/PBXGroup(path: 'TestProjectUITests')/PBXFileReference(path: 'TestProjectUITests.swift')" => 'DACE56B51C24A14D00E6ABB0',
64
+
65
+ # ├── TestProject
66
+ #    └── Products
67
+ #       ├── TestProject.app
68
+ "/PBXGroup/PBXGroup(name: 'Products')/PBXFileReference(path: 'TestProject.app')" => 'DACE56921C24A14D00E6ABB0',
69
+ "/PBXGroup/PBXGroup(name: 'Products')/PBXFileReference(path: 'TestProjectTests.xctest')" => 'DACE56A61C24A14D00E6ABB0',
70
+ "/PBXGroup/PBXGroup(name: 'Products')/PBXFileReference(path: 'TestProjectUITests.xctest')" => 'DACE56B11C24A14D00E6ABB0',
71
+ }
72
+
73
+ expectations.each do |path, uuid|
74
+ assert_equal path, result[uuid]
75
+ end
76
+
77
+ assert_equal [], result.keys - expectations.values
78
+
79
+ end
80
+
81
+ it 'correctly parses the remaining project objects' do
82
+
83
+ @parser.parse(object: main_group)
84
+ files_and_groups = @parser.visited.keys
85
+
86
+ @parser.parse(object: root_uuid)
87
+ result = @parser.visited.reject { |key, _| files_and_groups.include?(key) }
88
+
89
+ expectations = {
90
+
91
+ # ├── mainGroup
92
+ "/PBXProject" => "DACE568A1C24A14C00E6ABB0",
93
+
94
+ # ├── mainGroup
95
+ #    └── ProjectConfigurations
96
+ #       ├── Debug
97
+ #       ├── Release
98
+ "/PBXProject/XCConfigurationList" => "DACE568D1C24A14C00E6ABB0",
99
+ "/PBXProject/XCConfigurationList/XCBuildConfiguration(name: 'Debug')" => "DACE56B81C24A14D00E6ABB0",
100
+ "/PBXProject/XCConfigurationList/XCBuildConfiguration(name: 'Release')" => "DACE56B91C24A14D00E6ABB0",
101
+
102
+ # ├── mainGroup
103
+ #    └── Target = TestProject
104
+ #       └── Configurations
105
+ #          ├── Debug
106
+ #          ├── Release
107
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')" => "DACE56911C24A14D00E6ABB0",
108
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/XCConfigurationList" => "DACE56BA1C24A14D00E6ABB0",
109
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/XCConfigurationList/XCBuildConfiguration(name: 'Debug')" => "DACE56BB1C24A14D00E6ABB0",
110
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/XCConfigurationList/XCBuildConfiguration(name: 'Release')" => "DACE56BC1C24A14D00E6ABB0",
111
+
112
+ # ├── mainGroup
113
+ #    └── Target = TestProject
114
+ #       └── Build Sources
115
+ #          ├── ViewController.swift
116
+ #          ├── AppDelegate.swift
117
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXSourcesBuildPhase" => "DACE568E1C24A14D00E6ABB0",
118
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXSourcesBuildPhase/PBXBuildFile(path: 'ViewController.swift')" => "DACE56981C24A14D00E6ABB0",
119
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXSourcesBuildPhase/PBXBuildFile(path: 'AppDelegate.swift')" => "DACE56961C24A14D00E6ABB0",
120
+
121
+ # ├── mainGroup
122
+ #    └── Target = TestProject
123
+ #       └── Copy Frameworks
124
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXFrameworksBuildPhase" => "DACE568F1C24A14D00E6ABB0",
125
+
126
+ # ├── mainGroup
127
+ #    └── Target = TestProject
128
+ #       └── Copy Resources
129
+ #          ├── LaunchScreen.storyboard
130
+ #          ├── Assets.xcassets
131
+ #          ├── Main.storyboard
132
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXResourcesBuildPhase" => "DACE56901C24A14D00E6ABB0",
133
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXResourcesBuildPhase/PBXBuildFile(name: 'LaunchScreen.storyboard')" => "DACE56A01C24A14D00E6ABB0",
134
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXResourcesBuildPhase/PBXBuildFile(path: 'Assets.xcassets')" => "DACE569D1C24A14D00E6ABB0",
135
+ "/PBXProject/PBXNativeTarget(name: 'TestProject')/PBXResourcesBuildPhase/PBXBuildFile(name: 'Main.storyboard')" => "DACE569B1C24A14D00E6ABB0",
136
+
137
+ # ├── mainGroup
138
+ #    └── Target = TestProjectTests
139
+ #       └── Configurations
140
+ #          ├── Debug
141
+ #          ├── Release
142
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')" => "DACE56A51C24A14D00E6ABB0",
143
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/XCConfigurationList" => "DACE56BD1C24A14D00E6ABB0",
144
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/XCConfigurationList/XCBuildConfiguration(name: 'Debug')" => "DACE56BE1C24A14D00E6ABB0",
145
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/XCConfigurationList/XCBuildConfiguration(name: 'Release')" => "DACE56BF1C24A14D00E6ABB0",
146
+
147
+ # ├── mainGroup
148
+ #    └── Target = TestProjectTests
149
+ #       └── Build Sources
150
+ #          ├── TestProjectTests.swift
151
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXSourcesBuildPhase" => "DACE56A21C24A14D00E6ABB0",
152
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXSourcesBuildPhase/PBXBuildFile(path: 'TestProjectTests.swift')" => "DACE56AB1C24A14D00E6ABB0",
153
+
154
+ # ├── mainGroup
155
+ #    └── Target = TestProjectTests
156
+ #       └── Copy Frameworks
157
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXFrameworksBuildPhase" => "DACE56A31C24A14D00E6ABB0",
158
+
159
+ # ├── mainGroup
160
+ #    └── Target = TestProjectTests
161
+ #       └── Copy Resources
162
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXResourcesBuildPhase" => "DACE56A41C24A14D00E6ABB0",
163
+
164
+ # ├── mainGroup
165
+ #    └── Target = TestProjectTests
166
+ #       └── Dependencies
167
+ #          ├── TestProject
168
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXTargetDependency" => "DACE56A81C24A14D00E6ABB0",
169
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectTests')/PBXTargetDependency/PBXContainerItemProxy" => "DACE56A71C24A14D00E6ABB0",
170
+
171
+ # ├── mainGroup
172
+ #    └── Target = TestProjectUITests
173
+ #       └── Configurations
174
+ #          ├── Debug
175
+ #          ├── Release
176
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')" => "DACE56B01C24A14D00E6ABB0",
177
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/XCConfigurationList" => "DACE56C01C24A14D00E6ABB0",
178
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/XCConfigurationList/XCBuildConfiguration(name: 'Debug')" => "DACE56C11C24A14D00E6ABB0",
179
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/XCConfigurationList/XCBuildConfiguration(name: 'Release')" => "DACE56C21C24A14D00E6ABB0",
180
+
181
+ # ├── mainGroup
182
+ #    └── Target = TestProjectUITests
183
+ #       └── Build Sources
184
+ #          ├── TestProjectUITests.swift
185
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXSourcesBuildPhase" => "DACE56AD1C24A14D00E6ABB0",
186
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXSourcesBuildPhase/PBXBuildFile(path: 'TestProjectUITests.swift')" => "DACE56B61C24A14D00E6ABB0",
187
+
188
+ # ├── mainGroup
189
+ #    └── Target = TestProjectUITests
190
+ #       └── Copy Frameworks
191
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXFrameworksBuildPhase" => "DACE56AE1C24A14D00E6ABB0",
192
+
193
+ # ├── mainGroup
194
+ #    └── Target = TestProjectUITests
195
+ #       └── Copy Resources
196
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXResourcesBuildPhase" => "DACE56AF1C24A14D00E6ABB0",
197
+
198
+ # ├── mainGroup
199
+ #    └── Target = TestProjectUITests
200
+ #       └── Dependencies
201
+ #          ├── TestProject
202
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXTargetDependency" => "DACE56B31C24A14D00E6ABB0",
203
+ "/PBXProject/PBXNativeTarget(name: 'TestProjectUITests')/PBXTargetDependency/PBXContainerItemProxy" => "DACE56B21C24A14D00E6ABB0"
204
+ }
205
+
206
+ expectations.each do |path, uuid|
207
+ assert_equal path, result[uuid]
208
+ end
209
+
210
+ assert_equal [], result.keys - expectations.values
211
+
212
+ end
213
+
214
+ end
@@ -0,0 +1,116 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Xcunique::Sorter do
4
+
5
+ describe "when sorting groups" do
6
+ it "sorts alphabetically by their name" do
7
+ project = {
8
+ 'objects' => {
9
+ 'PARENT' => { 'children' => [ 'groupB', 'groupA' ] },
10
+ 'groupA' => { 'name' => 'A' },
11
+ 'groupB' => { 'name' => 'B' }
12
+ }
13
+ }
14
+
15
+ result = Xcunique::Sorter.new(project).sort
16
+
17
+ assert_equal [ 'groupA', 'groupB' ], result['objects']['PARENT']['children']
18
+ end
19
+
20
+ it "sorts alphabetically by their path" do
21
+ project = {
22
+ 'objects' => {
23
+ 'PARENT' => { 'children' => [ 'groupB', 'groupA' ] },
24
+ 'groupA' => { 'path' => 'A' },
25
+ 'groupB' => { 'path' => 'B' }
26
+ }
27
+ }
28
+
29
+ result = Xcunique::Sorter.new(project).sort
30
+
31
+ assert_equal [ 'groupA', 'groupB' ], result['objects']['PARENT']['children']
32
+ end
33
+
34
+ it "sorts alphabetically by their name then path" do
35
+ project = {
36
+ 'objects' => {
37
+ 'PARENT' => { 'children' => [ 'groupB', 'groupA' ] },
38
+ 'groupA' => { 'name' => 'A', 'path' => 'B' },
39
+ 'groupB' => { 'name' => 'B', 'path' => 'A' }
40
+ }
41
+ }
42
+
43
+ result = Xcunique::Sorter.new(project).sort
44
+
45
+ assert_equal [ 'groupA', 'groupB' ], result['objects']['PARENT']['children']
46
+ end
47
+ end
48
+
49
+ describe "when sorting files" do
50
+ it "sorts alphabetically by their name" do
51
+ project = {
52
+ 'objects' => {
53
+ 'PARENT' => { 'files' => [ 'buildFileB', 'buildFileA' ] },
54
+ 'buildFileA' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileA' },
55
+ 'buildFileB' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileB' },
56
+ 'fileA' => { 'name' => 'a.swift' },
57
+ 'fileB' => { 'name' => 'b.swift' }
58
+ }
59
+ }
60
+
61
+ result = Xcunique::Sorter.new(project).sort
62
+
63
+ assert_equal [ 'buildFileA', 'buildFileB' ], result['objects']['PARENT']['files']
64
+ end
65
+
66
+ it "sorts alphabetically by their path" do
67
+ project = {
68
+ 'objects' => {
69
+ 'PARENT' => { 'files' => [ 'buildFileB', 'buildFileA' ] },
70
+ 'buildFileA' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileA' },
71
+ 'buildFileB' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileB' },
72
+ 'fileA' => { 'path' => 'a.swift' },
73
+ 'fileB' => { 'path' => 'b.swift' }
74
+ }
75
+ }
76
+
77
+ result = Xcunique::Sorter.new(project).sort
78
+
79
+ assert_equal [ 'buildFileA', 'buildFileB' ], result['objects']['PARENT']['files']
80
+ end
81
+
82
+ it "sorts alphabetically by their name then path" do
83
+ project = {
84
+ 'objects' => {
85
+ 'PARENT' => { 'files' => [ 'buildFileB', 'buildFileA' ] },
86
+ 'buildFileA' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileA' },
87
+ 'buildFileB' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileB' },
88
+ 'fileA' => { 'name' => 'a.swift', 'path' => 'b/a.swift' },
89
+ 'fileB' => { 'name' => 'b.swift', 'path' => 'a/b.swift' }
90
+ }
91
+ }
92
+
93
+ result = Xcunique::Sorter.new(project).sort
94
+
95
+ assert_equal [ 'buildFileA', 'buildFileB' ], result['objects']['PARENT']['files']
96
+ end
97
+ end
98
+
99
+ describe "when sorting groups and files" do
100
+ it "sorts groups before files" do
101
+ project = {
102
+ 'objects' => {
103
+ 'PARENT' => { 'children' => [ 'buildFileA', 'groupA' ] },
104
+ 'buildFileA' => { 'isa' => 'PBXBuildFile', 'fileRef' => 'fileA' },
105
+ 'groupA' => { 'isa' => 'PBXGroup', 'name' => 'a' },
106
+ 'fileA' => { 'name' => 'a' },
107
+ }
108
+ }
109
+
110
+ result = Xcunique::Sorter.new(project).sort
111
+
112
+ assert_equal [ 'groupA', 'buildFileA' ], result['objects']['PARENT']['children']
113
+ end
114
+ end
115
+
116
+ end