1*082815dcSEvan Baconimport {
2*082815dcSEvan Bacon  findObjcFunctionCodeBlock,
3*082815dcSEvan Bacon  findObjcInterfaceCodeBlock,
4*082815dcSEvan Bacon  findSwiftFunctionCodeBlock,
5*082815dcSEvan Bacon  insertContentsInsideObjcFunctionBlock,
6*082815dcSEvan Bacon  insertContentsInsideObjcInterfaceBlock,
7*082815dcSEvan Bacon  insertContentsInsideSwiftClassBlock,
8*082815dcSEvan Bacon  insertContentsInsideSwiftFunctionBlock,
9*082815dcSEvan Bacon} from '../codeMod';
10*082815dcSEvan Bacon
11*082815dcSEvan Bacondescribe(findObjcInterfaceCodeBlock, () => {
12*082815dcSEvan Bacon  it('should find class interface', () => {
13*082815dcSEvan Bacon    const contents = `\
14*082815dcSEvan Bacon#import <Foundation/Foundation.h>
15*082815dcSEvan Bacon
16*082815dcSEvan Bacon@interface Foo : NSObject
17*082815dcSEvan Bacon{
18*082815dcSEvan Bacon  int value;
19*082815dcSEvan Bacon}
20*082815dcSEvan Bacon
21*082815dcSEvan Bacon- (void)doSomething;
22*082815dcSEvan Bacon@end
23*082815dcSEvan Bacon
24*082815dcSEvan Bacon// some comments`;
25*082815dcSEvan Bacon
26*082815dcSEvan Bacon    const expectContents = `\
27*082815dcSEvan Bacon@interface Foo : NSObject
28*082815dcSEvan Bacon{
29*082815dcSEvan Bacon  int value;
30*082815dcSEvan Bacon}
31*082815dcSEvan Bacon
32*082815dcSEvan Bacon- (void)doSomething;
33*082815dcSEvan Bacon@end`;
34*082815dcSEvan Bacon
35*082815dcSEvan Bacon    expect(findObjcInterfaceCodeBlock(contents, '@interface Foo')).toEqual({
36*082815dcSEvan Bacon      start: 35,
37*082815dcSEvan Bacon      end: 104,
38*082815dcSEvan Bacon      code: expectContents,
39*082815dcSEvan Bacon    });
40*082815dcSEvan Bacon  });
41*082815dcSEvan Bacon
42*082815dcSEvan Bacon  it('should find class category', () => {
43*082815dcSEvan Bacon    const contents = `\
44*082815dcSEvan Bacon@interface Foo() <SomeProtocol> {
45*082815dcSEvan Bacon  int value;
46*082815dcSEvan Bacon}
47*082815dcSEvan Bacon
48*082815dcSEvan Bacon- (void)doSomething;
49*082815dcSEvan Bacon@end
50*082815dcSEvan Bacon
51*082815dcSEvan Bacon// some comments`;
52*082815dcSEvan Bacon
53*082815dcSEvan Bacon    const expectContents = `\
54*082815dcSEvan Bacon@interface Foo() <SomeProtocol> {
55*082815dcSEvan Bacon  int value;
56*082815dcSEvan Bacon}
57*082815dcSEvan Bacon
58*082815dcSEvan Bacon- (void)doSomething;
59*082815dcSEvan Bacon@end`;
60*082815dcSEvan Bacon
61*082815dcSEvan Bacon    expect(findObjcInterfaceCodeBlock(contents, '@interface Foo')).toEqual({
62*082815dcSEvan Bacon      start: 0,
63*082815dcSEvan Bacon      end: 75,
64*082815dcSEvan Bacon      code: expectContents,
65*082815dcSEvan Bacon    });
66*082815dcSEvan Bacon  });
67*082815dcSEvan Bacon
68*082815dcSEvan Bacon  it('should find class implementation', () => {
69*082815dcSEvan Bacon    const contents = `\
70*082815dcSEvan Bacon#import <Foundation/Foundation.h>
71*082815dcSEvan Bacon
72*082815dcSEvan Bacon@interface Foo() <SomeProtocol> {
73*082815dcSEvan Bacon  int value;
74*082815dcSEvan Bacon}
75*082815dcSEvan Bacon
76*082815dcSEvan Bacon@implementation Foo
77*082815dcSEvan Bacon
78*082815dcSEvan Bacon- (void)doSomething
79*082815dcSEvan Bacon{
80*082815dcSEvan Bacon  // ...
81*082815dcSEvan Bacon}
82*082815dcSEvan Bacon
83*082815dcSEvan Bacon@end
84*082815dcSEvan Bacon
85*082815dcSEvan Bacon// some comments`;
86*082815dcSEvan Bacon
87*082815dcSEvan Bacon    const expectContents = `\
88*082815dcSEvan Bacon@implementation Foo
89*082815dcSEvan Bacon
90*082815dcSEvan Bacon- (void)doSomething
91*082815dcSEvan Bacon{
92*082815dcSEvan Bacon  // ...
93*082815dcSEvan Bacon}
94*082815dcSEvan Bacon
95*082815dcSEvan Bacon@end`;
96*082815dcSEvan Bacon
97*082815dcSEvan Bacon    expect(findObjcInterfaceCodeBlock(contents, '@implementation Foo')).toEqual({
98*082815dcSEvan Bacon      start: 85,
99*082815dcSEvan Bacon      end: 144,
100*082815dcSEvan Bacon      code: expectContents,
101*082815dcSEvan Bacon    });
102*082815dcSEvan Bacon  });
103*082815dcSEvan Bacon
104*082815dcSEvan Bacon  it('should returns null if not found', () => {
105*082815dcSEvan Bacon    expect(findObjcInterfaceCodeBlock('', '@interface NotFound')).toBe(null);
106*082815dcSEvan Bacon  });
107*082815dcSEvan Bacon});
108*082815dcSEvan Bacon
109*082815dcSEvan Bacondescribe(findObjcFunctionCodeBlock, () => {
110*082815dcSEvan Bacon  it('should find function selector without arguments', () => {
111*082815dcSEvan Bacon    const contents = `\
112*082815dcSEvan Bacon// comments
113*082815dcSEvan Bacon- (void)foo
114*082815dcSEvan Bacon{
115*082815dcSEvan Bacon  [self doSomething];
116*082815dcSEvan Bacon}
117*082815dcSEvan Bacon// comments`;
118*082815dcSEvan Bacon
119*082815dcSEvan Bacon    const expectContents = `\
120*082815dcSEvan Bacon{
121*082815dcSEvan Bacon  [self doSomething];
122*082815dcSEvan Bacon}`;
123*082815dcSEvan Bacon    expect(findObjcFunctionCodeBlock(contents, 'foo')).toEqual({
124*082815dcSEvan Bacon      start: 24,
125*082815dcSEvan Bacon      end: 48,
126*082815dcSEvan Bacon      code: expectContents,
127*082815dcSEvan Bacon    });
128*082815dcSEvan Bacon  });
129*082815dcSEvan Bacon
130*082815dcSEvan Bacon  it('should find function selector with one argument', () => {
131*082815dcSEvan Bacon    const contents = `\
132*082815dcSEvan Bacon// comments
133*082815dcSEvan Bacon- (void)foo:(NSString *)value
134*082815dcSEvan Bacon{
135*082815dcSEvan Bacon  [self doSomething];
136*082815dcSEvan Bacon}
137*082815dcSEvan Bacon// comments`;
138*082815dcSEvan Bacon
139*082815dcSEvan Bacon    const expectContents = `\
140*082815dcSEvan Bacon{
141*082815dcSEvan Bacon  [self doSomething];
142*082815dcSEvan Bacon}`;
143*082815dcSEvan Bacon    expect(findObjcFunctionCodeBlock(contents, 'foo:')).toEqual({
144*082815dcSEvan Bacon      start: 42,
145*082815dcSEvan Bacon      end: 66,
146*082815dcSEvan Bacon      code: expectContents,
147*082815dcSEvan Bacon    });
148*082815dcSEvan Bacon  });
149*082815dcSEvan Bacon
150*082815dcSEvan Bacon  it('should find function selector with two arguments', () => {
151*082815dcSEvan Bacon    const contents = `\
152*082815dcSEvan Bacon// comments
153*082815dcSEvan Bacon- (void)foo:(NSString *)value withBar:(NSString *)barValue
154*082815dcSEvan Bacon{
155*082815dcSEvan Bacon  [self doSomething];
156*082815dcSEvan Bacon}
157*082815dcSEvan Bacon// comments`;
158*082815dcSEvan Bacon
159*082815dcSEvan Bacon    const expectContents = `\
160*082815dcSEvan Bacon{
161*082815dcSEvan Bacon  [self doSomething];
162*082815dcSEvan Bacon}`;
163*082815dcSEvan Bacon    expect(findObjcFunctionCodeBlock(contents, 'foo:withBar:')).toEqual({
164*082815dcSEvan Bacon      start: 71,
165*082815dcSEvan Bacon      end: 95,
166*082815dcSEvan Bacon      code: expectContents,
167*082815dcSEvan Bacon    });
168*082815dcSEvan Bacon  });
169*082815dcSEvan Bacon
170*082815dcSEvan Bacon  it('should return null if selector function not found', () => {
171*082815dcSEvan Bacon    const contents = `
172*082815dcSEvan Bacon// comments
173*082815dcSEvan Bacon- (void)foo:(NSString *)value
174*082815dcSEvan Bacon{
175*082815dcSEvan Bacon  [self doSomething];
176*082815dcSEvan Bacon}
177*082815dcSEvan Bacon// comments`;
178*082815dcSEvan Bacon
179*082815dcSEvan Bacon    expect(findObjcFunctionCodeBlock(contents, 'foo')).toBe(null);
180*082815dcSEvan Bacon  });
181*082815dcSEvan Bacon});
182*082815dcSEvan Bacon
183*082815dcSEvan Bacondescribe(insertContentsInsideObjcFunctionBlock, () => {
184*082815dcSEvan Bacon  it('should support prepend code to the head', () => {
185*082815dcSEvan Bacon    const rawContents = `
186*082815dcSEvan Bacon- (void)doSomething:(NSString *)value
187*082815dcSEvan Bacon{
188*082815dcSEvan Bacon  [self doAnotherThing];
189*082815dcSEvan Bacon}`;
190*082815dcSEvan Bacon
191*082815dcSEvan Bacon    const expectContents = `
192*082815dcSEvan Bacon- (void)doSomething:(NSString *)value
193*082815dcSEvan Bacon{
194*082815dcSEvan Bacon  NSLog(@"value=%@", value);
195*082815dcSEvan Bacon  [self doAnotherThing];
196*082815dcSEvan Bacon}`;
197*082815dcSEvan Bacon
198*082815dcSEvan Bacon    expect(
199*082815dcSEvan Bacon      insertContentsInsideObjcFunctionBlock(
200*082815dcSEvan Bacon        rawContents,
201*082815dcSEvan Bacon        'doSomething:',
202*082815dcSEvan Bacon        'NSLog(@"value=%@", value);',
203*082815dcSEvan Bacon        {
204*082815dcSEvan Bacon          position: 'head',
205*082815dcSEvan Bacon        }
206*082815dcSEvan Bacon      )
207*082815dcSEvan Bacon    ).toEqual(expectContents);
208*082815dcSEvan Bacon  });
209*082815dcSEvan Bacon
210*082815dcSEvan Bacon  it('should support append code to the tail', () => {
211*082815dcSEvan Bacon    const rawContents = `
212*082815dcSEvan Bacon- (void)doSomething:(NSString *)value
213*082815dcSEvan Bacon{
214*082815dcSEvan Bacon  [self doAnotherThing];
215*082815dcSEvan Bacon}`;
216*082815dcSEvan Bacon
217*082815dcSEvan Bacon    const expectContents = `
218*082815dcSEvan Bacon- (void)doSomething:(NSString *)value
219*082815dcSEvan Bacon{
220*082815dcSEvan Bacon  [self doAnotherThing];
221*082815dcSEvan Bacon  NSLog(@"value=%@", value);
222*082815dcSEvan Bacon}`;
223*082815dcSEvan Bacon
224*082815dcSEvan Bacon    expect(
225*082815dcSEvan Bacon      insertContentsInsideObjcFunctionBlock(
226*082815dcSEvan Bacon        rawContents,
227*082815dcSEvan Bacon        'doSomething:',
228*082815dcSEvan Bacon        'NSLog(@"value=%@", value);',
229*082815dcSEvan Bacon        {
230*082815dcSEvan Bacon          position: 'tail',
231*082815dcSEvan Bacon        }
232*082815dcSEvan Bacon      )
233*082815dcSEvan Bacon    ).toEqual(expectContents);
234*082815dcSEvan Bacon  });
235*082815dcSEvan Bacon
236*082815dcSEvan Bacon  it('should support append code to the tail but before the last return', () => {
237*082815dcSEvan Bacon    const rawContents = `
238*082815dcSEvan Bacon- (BOOL)doSomething:(NSString *)value
239*082815dcSEvan Bacon{
240*082815dcSEvan Bacon  [self doAnotherThing];
241*082815dcSEvan Bacon  return YES;
242*082815dcSEvan Bacon}`;
243*082815dcSEvan Bacon
244*082815dcSEvan Bacon    const expectContents = `
245*082815dcSEvan Bacon- (BOOL)doSomething:(NSString *)value
246*082815dcSEvan Bacon{
247*082815dcSEvan Bacon  [self doAnotherThing];
248*082815dcSEvan Bacon  NSLog(@"value=%@", value);
249*082815dcSEvan Bacon  return YES;
250*082815dcSEvan Bacon}`;
251*082815dcSEvan Bacon
252*082815dcSEvan Bacon    expect(
253*082815dcSEvan Bacon      insertContentsInsideObjcFunctionBlock(
254*082815dcSEvan Bacon        rawContents,
255*082815dcSEvan Bacon        'doSomething:',
256*082815dcSEvan Bacon        'NSLog(@"value=%@", value);',
257*082815dcSEvan Bacon        {
258*082815dcSEvan Bacon          position: 'tailBeforeLastReturn',
259*082815dcSEvan Bacon        }
260*082815dcSEvan Bacon      )
261*082815dcSEvan Bacon    ).toEqual(expectContents);
262*082815dcSEvan Bacon  });
263*082815dcSEvan Bacon});
264*082815dcSEvan Bacon
265*082815dcSEvan Bacondescribe(insertContentsInsideObjcInterfaceBlock, () => {
266*082815dcSEvan Bacon  it('should support append new function into class implementation', () => {
267*082815dcSEvan Bacon    const contents = `\
268*082815dcSEvan Bacon@interface Foo() <SomeProtocol> {
269*082815dcSEvan Bacon  int value;
270*082815dcSEvan Bacon}
271*082815dcSEvan Bacon
272*082815dcSEvan Bacon@implementation Foo
273*082815dcSEvan Bacon
274*082815dcSEvan Bacon- (void)doSomething
275*082815dcSEvan Bacon{
276*082815dcSEvan Bacon  // ...
277*082815dcSEvan Bacon}
278*082815dcSEvan Bacon
279*082815dcSEvan Bacon@end`;
280*082815dcSEvan Bacon
281*082815dcSEvan Bacon    const expectContents = `\
282*082815dcSEvan Bacon@interface Foo() <SomeProtocol> {
283*082815dcSEvan Bacon  int value;
284*082815dcSEvan Bacon}
285*082815dcSEvan Bacon
286*082815dcSEvan Bacon@implementation Foo
287*082815dcSEvan Bacon
288*082815dcSEvan Bacon- (void)doSomething
289*082815dcSEvan Bacon{
290*082815dcSEvan Bacon  // ...
291*082815dcSEvan Bacon}
292*082815dcSEvan Bacon
293*082815dcSEvan Bacon- (BOOL)isFoo
294*082815dcSEvan Bacon{
295*082815dcSEvan Bacon  return YES;
296*082815dcSEvan Bacon}
297*082815dcSEvan Bacon
298*082815dcSEvan Bacon@end`;
299*082815dcSEvan Bacon
300*082815dcSEvan Bacon    expect(
301*082815dcSEvan Bacon      insertContentsInsideObjcInterfaceBlock(
302*082815dcSEvan Bacon        contents,
303*082815dcSEvan Bacon        '@interface Foo',
304*082815dcSEvan Bacon        `\
305*082815dcSEvan Bacon- (BOOL)isFoo
306*082815dcSEvan Bacon{
307*082815dcSEvan Bacon  return YES;
308*082815dcSEvan Bacon}\n
309*082815dcSEvan Bacon`,
310*082815dcSEvan Bacon        { position: 'tail' }
311*082815dcSEvan Bacon      )
312*082815dcSEvan Bacon    ).toEqual(expectContents);
313*082815dcSEvan Bacon  });
314*082815dcSEvan Bacon});
315*082815dcSEvan Bacon
316*082815dcSEvan Bacondescribe(findSwiftFunctionCodeBlock, () => {
317*082815dcSEvan Bacon  it('should find function with match selector', () => {
318*082815dcSEvan Bacon    const contents = `
319*082815dcSEvan Baconclass Foo: NSObject {
320*082815dcSEvan Bacon  func doSomething() {
321*082815dcSEvan Bacon    print("Hello!")
322*082815dcSEvan Bacon  }
323*082815dcSEvan Bacon
324*082815dcSEvan Bacon  func doSomething(forName name: String) -> Bool {
325*082815dcSEvan Bacon    return true
326*082815dcSEvan Bacon  }
327*082815dcSEvan Bacon
328*082815dcSEvan Bacon  func doSomething(_ name: String, withValue value: String) {
329*082815dcSEvan Bacon    print("Hello \\(name) - value[\\(value)]!")
330*082815dcSEvan Bacon  }
331*082815dcSEvan Bacon}
332*082815dcSEvan Bacon`;
333*082815dcSEvan Bacon    expect(findSwiftFunctionCodeBlock(contents, 'doSomething(_:withValue:)')).toEqual({
334*082815dcSEvan Bacon      start: 203,
335*082815dcSEvan Bacon      end: 253,
336*082815dcSEvan Bacon      code: ['{', '    print("Hello \\(name) - value[\\(value)]!")', '  }'].join('\n'),
337*082815dcSEvan Bacon    });
338*082815dcSEvan Bacon  });
339*082815dcSEvan Bacon});
340*082815dcSEvan Bacon
341*082815dcSEvan Bacondescribe(insertContentsInsideSwiftClassBlock, () => {
342*082815dcSEvan Bacon  it('should support adding new property inside class code block', () => {
343*082815dcSEvan Bacon    const contents = `
344*082815dcSEvan Bacon// comments
345*082815dcSEvan Baconclass Foo: NSObject {
346*082815dcSEvan Bacon  func doSomething() {
347*082815dcSEvan Bacon    // ...
348*082815dcSEvan Bacon  }
349*082815dcSEvan Bacon}`;
350*082815dcSEvan Bacon
351*082815dcSEvan Bacon    const expectContents = `
352*082815dcSEvan Bacon// comments
353*082815dcSEvan Baconclass Foo: NSObject {
354*082815dcSEvan Bacon  var Value: String?
355*082815dcSEvan Bacon
356*082815dcSEvan Bacon  func doSomething() {
357*082815dcSEvan Bacon    // ...
358*082815dcSEvan Bacon  }
359*082815dcSEvan Bacon}`;
360*082815dcSEvan Bacon
361*082815dcSEvan Bacon    expect(
362*082815dcSEvan Bacon      insertContentsInsideSwiftClassBlock(contents, 'class Foo', '\n  var Value: String?\n', {
363*082815dcSEvan Bacon        position: 'head',
364*082815dcSEvan Bacon      })
365*082815dcSEvan Bacon    ).toEqual(expectContents);
366*082815dcSEvan Bacon  });
367*082815dcSEvan Bacon});
368*082815dcSEvan Bacon
369*082815dcSEvan Bacondescribe(insertContentsInsideSwiftFunctionBlock, () => {
370*082815dcSEvan Bacon  it('should support prepend code to the head', () => {
371*082815dcSEvan Bacon    const rawContents = `
372*082815dcSEvan Baconfunc doSomething(_ value: String!) {
373*082815dcSEvan Bacon  self.doAnotherThing()
374*082815dcSEvan Bacon}`;
375*082815dcSEvan Bacon
376*082815dcSEvan Bacon    const expectContents = `
377*082815dcSEvan Baconfunc doSomething(_ value: String!) {
378*082815dcSEvan Bacon  print("value=\\(value)")
379*082815dcSEvan Bacon  self.doAnotherThing()
380*082815dcSEvan Bacon}`;
381*082815dcSEvan Bacon
382*082815dcSEvan Bacon    expect(
383*082815dcSEvan Bacon      insertContentsInsideSwiftFunctionBlock(
384*082815dcSEvan Bacon        rawContents,
385*082815dcSEvan Bacon        'doSomething(_:)',
386*082815dcSEvan Bacon        'print("value=\\(value)")',
387*082815dcSEvan Bacon        {
388*082815dcSEvan Bacon          position: 'head',
389*082815dcSEvan Bacon        }
390*082815dcSEvan Bacon      )
391*082815dcSEvan Bacon    ).toEqual(expectContents);
392*082815dcSEvan Bacon  });
393*082815dcSEvan Bacon
394*082815dcSEvan Bacon  it('should support append code to the tail', () => {
395*082815dcSEvan Bacon    const rawContents = `
396*082815dcSEvan Baconfunc doSomething(_ value: String!) {
397*082815dcSEvan Bacon  self.doAnotherThing()
398*082815dcSEvan Bacon}`;
399*082815dcSEvan Bacon
400*082815dcSEvan Bacon    const expectContents = `
401*082815dcSEvan Baconfunc doSomething(_ value: String!) {
402*082815dcSEvan Bacon  self.doAnotherThing()
403*082815dcSEvan Bacon  print("value=\\(value)")
404*082815dcSEvan Bacon}`;
405*082815dcSEvan Bacon
406*082815dcSEvan Bacon    expect(
407*082815dcSEvan Bacon      insertContentsInsideSwiftFunctionBlock(
408*082815dcSEvan Bacon        rawContents,
409*082815dcSEvan Bacon        'doSomething(_:)',
410*082815dcSEvan Bacon        'print("value=\\(value)")',
411*082815dcSEvan Bacon        {
412*082815dcSEvan Bacon          position: 'tail',
413*082815dcSEvan Bacon        }
414*082815dcSEvan Bacon      )
415*082815dcSEvan Bacon    ).toEqual(expectContents);
416*082815dcSEvan Bacon  });
417*082815dcSEvan Bacon
418*082815dcSEvan Bacon  it('should support append code to the tail but before the last return', () => {
419*082815dcSEvan Bacon    const rawContents = `
420*082815dcSEvan Baconfunc doSomething(_ value: String!) -> Bool {
421*082815dcSEvan Bacon  self.doAnotherThing()
422*082815dcSEvan Bacon  return true
423*082815dcSEvan Bacon}`;
424*082815dcSEvan Bacon
425*082815dcSEvan Bacon    const expectContents = `
426*082815dcSEvan Baconfunc doSomething(_ value: String!) -> Bool {
427*082815dcSEvan Bacon  self.doAnotherThing()
428*082815dcSEvan Bacon  print("value=\\(value)")
429*082815dcSEvan Bacon  return true
430*082815dcSEvan Bacon}`;
431*082815dcSEvan Bacon
432*082815dcSEvan Bacon    expect(
433*082815dcSEvan Bacon      insertContentsInsideSwiftFunctionBlock(
434*082815dcSEvan Bacon        rawContents,
435*082815dcSEvan Bacon        'doSomething(_:)',
436*082815dcSEvan Bacon        'print("value=\\(value)")',
437*082815dcSEvan Bacon        {
438*082815dcSEvan Bacon          position: 'tailBeforeLastReturn',
439*082815dcSEvan Bacon        }
440*082815dcSEvan Bacon      )
441*082815dcSEvan Bacon    ).toEqual(expectContents);
442*082815dcSEvan Bacon  });
443*082815dcSEvan Bacon});
444