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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/Guardfile +22 -0
- data/LICENSE.txt +22 -0
- data/README.md +73 -0
- data/Rakefile +11 -0
- data/bin/xcunique +5 -0
- data/lib/json2plist/json2plist +21 -0
- data/lib/xcunique.rb +23 -0
- data/lib/xcunique/cli.rb +40 -0
- data/lib/xcunique/hash_ext.rb +25 -0
- data/lib/xcunique/helpers.rb +26 -0
- data/lib/xcunique/options.rb +68 -0
- data/lib/xcunique/parser.rb +54 -0
- data/lib/xcunique/sorter.rb +51 -0
- data/lib/xcunique/uniquifier.rb +36 -0
- data/lib/xcunique/version.rb +3 -0
- data/spec/fixtures/TestProject.json +548 -0
- data/spec/fixtures/TestProject/TestProject.xcodeproj/project.pbxproj +510 -0
- data/spec/fixtures/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/spec/fixtures/TestProject/TestProject.xcodeproj/project.xcworkspace/xcuserdata/paul.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/spec/fixtures/TestProject/TestProject.xcodeproj/xcuserdata/paul.xcuserdatad/xcschemes/TestProject.xcscheme +111 -0
- data/spec/fixtures/TestProject/TestProject.xcodeproj/xcuserdata/paul.xcuserdatad/xcschemes/xcschememanagement.plist +47 -0
- data/spec/fixtures/TestProject/TestProject/AppDelegate.swift +46 -0
- data/spec/fixtures/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- data/spec/fixtures/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard +27 -0
- data/spec/fixtures/TestProject/TestProject/Base.lproj/Main.storyboard +26 -0
- data/spec/fixtures/TestProject/TestProject/Info.plist +47 -0
- data/spec/fixtures/TestProject/TestProject/ViewController.swift +25 -0
- data/spec/fixtures/TestProject/TestProjectTests/Info.plist +24 -0
- data/spec/fixtures/TestProject/TestProjectTests/TestProjectTests.swift +36 -0
- data/spec/fixtures/TestProject/TestProjectUITests/Info.plist +24 -0
- data/spec/fixtures/TestProject/TestProjectUITests/TestProjectUITests.swift +36 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/xcunique/hash_ext_spec.rb +36 -0
- data/spec/xcunique/helpers_spec.rb +58 -0
- data/spec/xcunique/parser_spec.rb +214 -0
- data/spec/xcunique/sorter_spec.rb +116 -0
- data/xcunique.gemspec +26 -0
- 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 | 
            +
            }
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
| @@ -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
         |