-
Notifications
You must be signed in to change notification settings - Fork 286
Expand file tree
/
Copy pathGTIndexSpec.m
More file actions
309 lines (244 loc) · 11.9 KB
/
Copy pathGTIndexSpec.m
File metadata and controls
309 lines (244 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//
// GTIndexSpec.m
// ObjectiveGitFramework
//
// Created by Josh Abernathy on 5/10/13.
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Nimble/Nimble.h>
#import <ObjectiveGit/ObjectiveGit.h>
#import <Quick/Quick.h>
#import "QuickSpec+GTFixtures.h"
QuickSpecBegin(GTIndexSpec)
__block GTRepository *repository;
__block GTIndex *index;
beforeEach(^{
repository = self.testAppFixtureRepository;
index = [repository indexWithError:NULL];
expect(index).notTo(beNil());
BOOL success = [index refresh:NULL];
expect(@(success)).to(beTruthy());
});
it(@"should count the entries", ^{
expect(@(index.entryCount)).to(equal(@24));
});
it(@"should clear all entries", ^{
[index clear:NULL];
expect(@(index.entryCount)).to(equal(@0));
});
it(@"should read entry properties", ^{
GTIndexEntry *entry = [index entryAtIndex:0];
expect(entry).notTo(beNil());
expect(entry.path).to(equal(@".gitignore"));
expect(@(entry.staged)).to(beFalsy());
});
it(@"should write to the repository and return a tree", ^{
GTTree *tree = [index writeTree:NULL];
expect(tree).notTo(beNil());
expect(@(tree.entryCount)).to(equal(@23));
expect(tree.repository).to(equal(repository));
});
it(@"should write to a specific repository and return a tree", ^{
GTRepository *repository = self.bareFixtureRepository;
NSArray *branches = [repository branches:NULL];
GTCommit *masterCommit = [branches[0] targetCommitWithError:NULL];
GTCommit *packedCommit = [branches[1] targetCommitWithError:NULL];
expect(masterCommit).notTo(beNil());
expect(packedCommit).notTo(beNil());
GTIndex *index = [masterCommit.tree merge:packedCommit.tree ancestor:NULL error:NULL];
GTTree *mergedTree = [index writeTreeToRepository:repository error:NULL];
expect(index).notTo(beNil());
expect(mergedTree).notTo(beNil());
expect(@(mergedTree.entryCount)).to(equal(@5));
expect(mergedTree.repository).to(equal(repository));
});
it(@"should create an index in memory", ^{
GTIndex *memoryIndex = [GTIndex inMemoryIndexWithRepository:repository error:NULL];
expect(memoryIndex).notTo(beNil());
expect(memoryIndex.fileURL).to(beNil());
});
it(@"should add the contents of a tree", ^{
GTCommit *headCommit = [repository lookUpObjectByRevParse:@"HEAD" error:NULL];
expect(headCommit).notTo(beNil());
GTTree *headTree = headCommit.tree;
expect(@(headTree.entryCount)).to(beGreaterThan(@0));
GTIndex *memoryIndex = [GTIndex inMemoryIndexWithRepository:index.repository error:NULL];
expect(memoryIndex).notTo(beNil());
expect(@(memoryIndex.entryCount)).to(equal(@0));
BOOL success = [memoryIndex addContentsOfTree:headTree error:NULL];
expect(@(success)).to(beTruthy());
[headTree enumerateEntriesWithOptions:GTTreeEnumerationOptionPre error:NULL block:^(GTTreeEntry *treeEntry, NSString *root, BOOL *stop) {
if (treeEntry.type == GTObjectTypeBlob) {
NSString *path = [root stringByAppendingString:treeEntry.name];
GTIndexEntry *indexEntry = [memoryIndex entryWithPath:path];
expect(indexEntry).notTo(beNil());
}
return YES;
}];
});
describe(@"conflict enumeration", ^{
it(@"should correctly find no conflicts", ^{
expect(@(index.hasConflicts)).to(beFalsy());
});
it(@"should immediately return YES when enumerating no conflicts", ^{
__block BOOL blockRan = NO;
BOOL enumerationResult = [index enumerateConflictedFilesWithError:NULL usingBlock:^(GTIndexEntry *ancestor, GTIndexEntry *ours, GTIndexEntry *theirs, BOOL *stop) {
blockRan = YES;
}];
expect(@(enumerationResult)).to(beTruthy());
expect(@(blockRan)).to(beFalsy());
});
it(@"should correctly report conflicts", ^{
index = [self.conflictedFixtureRepository indexWithError:NULL];
expect(index).notTo(beNil());
expect(@(index.hasConflicts)).to(beTruthy());
});
it(@"should enumerate conflicts successfully", ^{
index = [self.conflictedFixtureRepository indexWithError:NULL];
expect(index).notTo(beNil());
NSError *err = NULL;
__block NSUInteger count = 0;
NSArray *expectedPaths = @[ @"TestAppDelegate.h", @"main.m" ];
BOOL enumerationResult = [index enumerateConflictedFilesWithError:&err usingBlock:^(GTIndexEntry *ancestor, GTIndexEntry *ours, GTIndexEntry *theirs, BOOL *stop) {
expect(ours.path).to(equal(expectedPaths[count]));
count ++;
}];
expect(@(enumerationResult)).to(beTruthy());
expect(err).to(beNil());
expect(@(count)).to(equal(@2));
});
});
describe(@"updating pathspecs", ^{
NSString *fileName = @"REAME_";
beforeEach(^{
index = [self.testAppFixtureRepository indexWithError:NULL];
NSString *filePath = [self.testAppFixtureRepository.fileURL.path stringByAppendingPathComponent:fileName];
[@"The wild west..." writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:NULL];
expect(index).notTo(beNil());
expect(@([index.repository statusForFile:fileName success:NULL error:NULL])).to(equal(@(GTFileStatusModifiedInWorktree)));
});
it(@"should update the Index", ^{
BOOL success = [index updatePathspecs:@[ fileName ] error:NULL passingTest:^(NSString *matchedPathspec, NSString *path, BOOL *stop) {
expect(matchedPathspec).to(equal(fileName));
expect(path).to(equal(fileName));
return YES;
}];
expect(@(success)).to(beTruthy());
expect(@([index.repository statusForFile:fileName success:NULL error:NULL])).to(equal(@(GTFileStatusModifiedInIndex)));
});
it(@"should skip a specific file", ^{
BOOL success = [index updatePathspecs:NULL error:NULL passingTest:^(NSString *matchedPathspec, NSString *path, BOOL *stop) {
if ([path.lastPathComponent isEqualToString:fileName]) {
return NO;
} else {
return YES;
}
}];
expect(@(success)).to(beTruthy());
expect(@([index.repository statusForFile:fileName success:NULL error:NULL])).to(equal(@(GTFileStatusModifiedInWorktree)));
});
it(@"should stop be able to stop early", ^{
NSString *otherFileName = @"TestAppDelegate.h";
[@"WELP" writeToFile:[self.testAppFixtureRepository.fileURL.path stringByAppendingPathComponent:otherFileName] atomically:NO encoding:NSUTF8StringEncoding error:NULL];
BOOL success = [index updatePathspecs:NULL error:NULL passingTest:^(NSString *matchedPathspec, NSString *path, BOOL *stop) {
if ([path.lastPathComponent isEqualToString:fileName]) {
*stop = YES;
return YES;
}
return YES;
}];
expect(@(success)).to(beTruthy());
expect(@([index.repository statusForFile:fileName success:NULL error:NULL])).to(equal(@(GTFileStatusModifiedInIndex)));
expect(@([index.repository statusForFile:otherFileName success:NULL error:NULL])).to(equal(@(GTFileStatusModifiedInWorktree)));
});
});
describe(@"adding files", ^{
__block GTRepository *repo;
__block GTConfiguration *configuration;
__block GTIndex *index;
__block NSURL *fileURL;
__block NSURL *renamedFileURL;
NSString *filename = @"Åströmm";
NSString *renamedFilename = [filename stringByAppendingString:filename];
NSDictionary *renamedOptions = @{ GTRepositoryStatusOptionsFlagsKey: @(GTRepositoryStatusFlagsIncludeIgnored | GTRepositoryStatusFlagsIncludeUntracked | GTRepositoryStatusFlagsRecurseUntrackedDirectories | GTRepositoryStatusFlagsRenamesHeadToIndex | GTRepositoryStatusFlagsIncludeUnmodified) };
BOOL (^fileStatusEqualsExpected)(NSString *filename, GTStatusDeltaStatus headToIndexStatus, GTStatusDeltaStatus indexToWorkingDirectoryStatus) = ^(NSString *filename, GTStatusDeltaStatus headToIndexStatus, GTStatusDeltaStatus indexToWorkingDirectoryStatus) {
return [index.repository enumerateFileStatusWithOptions:renamedOptions error:NULL usingBlock:^(GTStatusDelta *headToIndex, GTStatusDelta *indexToWorkingDirectory, BOOL *stop) {
if (![headToIndex.newFile.path isEqualToString:filename]) return;
expect(@(headToIndex.status)).to(equal(@(headToIndexStatus)));
expect(@(indexToWorkingDirectory.status)).to(equal(@(indexToWorkingDirectoryStatus)));
}];
};
beforeEach(^{
expect(filename).to(equal([filename precomposedStringWithCanonicalMapping]));
repo = self.testUnicodeFixtureRepository;
configuration = [repo configurationWithError:NULL];
[configuration setBool:false forKey:@"core.precomposeunicode"];
expect(@([configuration boolForKey:@"core.precomposeunicode"])).to(beFalsy());
index = [repo indexWithError:NULL];
NSString *path = [repo.fileURL.path stringByAppendingPathComponent:filename];
fileURL = [NSURL fileURLWithPath:path isDirectory:NO];
NSString *newPath = [repo.fileURL.path stringByAppendingPathComponent:renamedFilename];
renamedFileURL = [NSURL fileURLWithPath:newPath isDirectory:NO];
});
it(@"it preserves decomposed Unicode in index paths with precomposeunicode disabled", ^{
NSString *decomposedFilename = [filename decomposedStringWithCanonicalMapping];
GTIndexEntry *entry = [index entryWithPath:decomposedFilename error:NULL];
expect(@(fileStatusEqualsExpected(entry.path, GTStatusDeltaStatusUnmodified, GTStatusDeltaStatusUnmodified))).to(beTruthy());
expect(@([[NSFileManager defaultManager] moveItemAtURL:fileURL toURL:renamedFileURL error:NULL])).to(beTruthy());
entry = [index entryWithPath:decomposedFilename error:NULL];
expect(@(fileStatusEqualsExpected(entry.path, GTStatusDeltaStatusUnmodified, GTStatusDeltaStatusDeleted))).to(beTruthy());
[index removeFile:filename error:NULL];
[index addFile:renamedFilename error:NULL];
[index write:NULL];
entry = [index entryWithPath:[renamedFilename decomposedStringWithCanonicalMapping] error:NULL];
expect(@(fileStatusEqualsExpected(entry.path, GTStatusDeltaStatusRenamed, GTStatusDeltaStatusUnmodified))).to(beTruthy());
});
it(@"it preserves precomposed Unicode in index paths with precomposeunicode enabled", ^{
GTIndexEntry *fileEntry = [index entryWithPath:[filename decomposedStringWithCanonicalMapping] error:NULL];
expect(fileEntry).notTo(beNil());
expect(@(fileStatusEqualsExpected(fileEntry.path, GTStatusDeltaStatusUnmodified, GTStatusDeltaStatusUnmodified))).to(beTruthy());
[configuration setBool:true forKey:@"core.precomposeunicode"];
expect(@([configuration boolForKey:@"core.precomposeunicode"])).to(beTruthy());
GTIndexEntry *decomposedFileEntry = [index entryWithPath:[filename decomposedStringWithCanonicalMapping] error:NULL];
expect(decomposedFileEntry).notTo(beNil());
// This check will fail if GIT_USE_ICONV is not enabled
expect(@(fileStatusEqualsExpected(decomposedFileEntry.path, GTStatusDeltaStatusUnmodified, GTStatusDeltaStatusDeleted))).to(beTruthy());
expect(@([[NSFileManager defaultManager] moveItemAtURL:fileURL toURL:renamedFileURL error:NULL])).to(beTruthy());
GTIndexEntry *precomposedFileEntry = [index entryWithPath:filename error:NULL];
expect(precomposedFileEntry).to(beNil());
decomposedFileEntry = [index entryWithPath:[filename decomposedStringWithCanonicalMapping] error:NULL];
expect(decomposedFileEntry).notTo(beNil());
expect(@(fileStatusEqualsExpected(decomposedFileEntry.path, GTStatusDeltaStatusUnmodified, GTStatusDeltaStatusDeleted))).to(beTruthy());
[index removeFile:filename error:NULL];
[index addFile:renamedFilename error:NULL];
[index write:NULL];
GTIndexEntry *precomposedRenamedFileEntry = [index entryWithPath:renamedFilename error:NULL];
expect(precomposedRenamedFileEntry).notTo(beNil());
expect(@(fileStatusEqualsExpected(precomposedFileEntry.path, GTStatusDeltaStatusRenamed, GTStatusDeltaStatusUntracked))).to(beTruthy());
});
});
describe(@"adding data", ^{
__block GTRepository *repo;
__block GTIndex *index;
__block NSError *error;
beforeEach(^{
error = nil;
repo = self.testUnicodeFixtureRepository;
// Not sure why but it doesn't work with an in memory index
// index = [GTIndex inMemoryIndexWithRepository:repo error:&error];
index = [repo indexWithError:&error];
expect(error).to(beNil());
});
it(@"should store data at given path", ^{
NSData *data = [NSData dataWithBytes:"foo" length:4];
[index addData:data withPath:@"bar/foo" error:&error];
expect(error).to(beNil());
GTIndexEntry *entry = [index entryWithPath:@"bar/foo" error:&error];
expect(entry).notTo(beNil());
expect(error).to(beNil());
});
});
afterEach(^{
[self tearDown];
});
QuickSpecEnd