Annotation of pkgsrc/pkgtools/pkglint/files/autofix_test.go, Revision 1.23
1.14 rillig 1: package pkglint
1.1 rillig 2:
1.5 rillig 3: import (
4: "gopkg.in/check.v1"
1.10 rillig 5: "os"
6: "runtime"
1.5 rillig 7: "strings"
8: )
1.1 rillig 9:
1.12 rillig 10: func (s *Suite) Test_Autofix_Warnf__duplicate(c *check.C) {
11: t := s.Init(c)
12:
13: line := t.NewLine("DESCR", 1, "Description of the package")
14:
15: fix := line.Autofix()
16: fix.Warnf("Warning 1.")
17: t.ExpectPanic(
18: func() { fix.Warnf("Warning 2.") },
19: "Pkglint internal error: Autofix can only have a single diagnostic.")
20: }
21:
22: func (s *Suite) Test_Autofix__default_leaves_line_unchanged(c *check.C) {
23: t := s.Init(c)
24:
1.16 rillig 25: t.SetUpCommandLine("--source")
26: mklines := t.SetUpFileMkLines("Makefile",
1.12 rillig 27: "# row 1 \\",
28: "continuation of row 1")
29: line := mklines.lines.Lines[0]
30:
31: fix := line.Autofix()
32: fix.Warnf("Row should be replaced with line.")
33: fix.Replace("row", "line")
34: fix.ReplaceRegex(`row \d+`, "the above line", -1)
35: fix.InsertBefore("above")
36: fix.InsertAfter("below")
37: fix.Delete()
38: fix.Apply()
39:
40: c.Check(fix.RawText(), equals, ""+
41: "# row 1 \\\n"+
42: "continuation of row 1\n")
43: t.CheckOutputLines(
44: ">\t# row 1 \\",
45: ">\tcontinuation of row 1",
46: "WARN: ~/Makefile:1--2: Row should be replaced with line.")
47: c.Check(fix.modified, equals, true)
48: }
49:
50: func (s *Suite) Test_Autofix__show_autofix_modifies_line(c *check.C) {
51: t := s.Init(c)
52:
1.16 rillig 53: t.SetUpCommandLine("--source", "--show-autofix")
54: mklines := t.SetUpFileMkLines("Makefile",
1.12 rillig 55: "# row 1 \\",
56: "continuation of row 1")
57: line := mklines.lines.Lines[0]
58:
59: fix := line.Autofix()
60: fix.Warnf("Row should be replaced with line.")
61: fix.ReplaceAfter("", "row", "line")
62: fix.ReplaceRegex(`row \d+`, "the above line", -1)
63: fix.InsertBefore("above")
64: fix.InsertAfter("below")
65: fix.Delete()
66: fix.Apply()
67:
68: c.Check(fix.RawText(), equals, ""+
69: "above\n"+
70: "below\n")
71: t.CheckOutputLines(
72: "WARN: ~/Makefile:1--2: Row should be replaced with line.",
73: "AUTOFIX: ~/Makefile:1: Replacing \"row\" with \"line\".",
74: "AUTOFIX: ~/Makefile:2: Replacing \"row 1\" with \"the above line\".",
75: "AUTOFIX: ~/Makefile:1: Inserting a line \"above\" before this line.",
76: "AUTOFIX: ~/Makefile:2: Inserting a line \"below\" after this line.",
77: "AUTOFIX: ~/Makefile:1: Deleting this line.",
78: "AUTOFIX: ~/Makefile:2: Deleting this line.",
79: "+\tabove",
80: "-\t# row 1 \\",
81: "-\tcontinuation of row 1",
82: "+\tbelow")
83: c.Check(fix.modified, equals, true)
84: }
85:
86: func (s *Suite) Test_Autofix_ReplaceAfter__autofix(c *check.C) {
87: t := s.Init(c)
88:
1.16 rillig 89: t.SetUpCommandLine("--autofix", "--source")
90: mklines := t.SetUpFileMkLines("Makefile",
1.12 rillig 91: "# line 1 \\",
92: "continuation 1 \\",
93: "continuation 2")
94:
95: fix := mklines.lines.Lines[0].Autofix()
96: fix.Warnf("N should be replaced with V.")
97: fix.ReplaceAfter("", "n", "v")
98: fix.Apply()
99:
100: t.CheckOutputLines(
101: "AUTOFIX: ~/Makefile:1: Replacing \"n\" with \"v\".",
102: "-\t# line 1 \\",
103: "+\t# live 1 \\",
1.13 rillig 104: "\tcontinuation 1 \\",
105: "\tcontinuation 2")
1.12 rillig 106: }
107:
1.11 rillig 108: func (s *Suite) Test_Autofix_ReplaceRegex__show_autofix(c *check.C) {
1.2 rillig 109: t := s.Init(c)
110:
1.16 rillig 111: t.SetUpCommandLine("--show-autofix")
112: lines := t.SetUpFileLines("Makefile",
1.2 rillig 113: "line1",
114: "line2",
115: "line3")
1.1 rillig 116:
1.12 rillig 117: fix := lines.Lines[1].Autofix()
1.1 rillig 118: fix.Warnf("Something's wrong here.")
1.3 rillig 119: fix.ReplaceRegex(`.`, "X", -1)
1.1 rillig 120: fix.Apply()
121: SaveAutofixChanges(lines)
122:
1.12 rillig 123: c.Check(lines.Lines[1].raw[0].textnl, equals, "XXXXX\n")
1.2 rillig 124: t.CheckFileLines("Makefile",
125: "line1",
126: "line2",
127: "line3")
128: t.CheckOutputLines(
1.1 rillig 129: "WARN: ~/Makefile:2: Something's wrong here.",
1.3 rillig 130: "AUTOFIX: ~/Makefile:2: Replacing \"l\" with \"X\".",
131: "AUTOFIX: ~/Makefile:2: Replacing \"i\" with \"X\".",
132: "AUTOFIX: ~/Makefile:2: Replacing \"n\" with \"X\".",
133: "AUTOFIX: ~/Makefile:2: Replacing \"e\" with \"X\".",
134: "AUTOFIX: ~/Makefile:2: Replacing \"2\" with \"X\".")
1.1 rillig 135: }
136:
1.11 rillig 137: func (s *Suite) Test_Autofix_ReplaceRegex__autofix(c *check.C) {
1.2 rillig 138: t := s.Init(c)
139:
1.16 rillig 140: t.SetUpCommandLine("--autofix", "--source")
141: lines := t.SetUpFileLines("Makefile",
1.2 rillig 142: "line1",
143: "line2",
144: "line3")
1.1 rillig 145:
1.12 rillig 146: fix := lines.Lines[1].Autofix()
1.1 rillig 147: fix.Warnf("Something's wrong here.")
1.3 rillig 148: fix.ReplaceRegex(`.`, "X", 3)
1.1 rillig 149: fix.Apply()
150:
1.3 rillig 151: t.CheckOutputLines(
152: "AUTOFIX: ~/Makefile:2: Replacing \"l\" with \"X\".",
153: "AUTOFIX: ~/Makefile:2: Replacing \"i\" with \"X\".",
154: "AUTOFIX: ~/Makefile:2: Replacing \"n\" with \"X\".",
155: "-\tline2",
156: "+\tXXXe2")
157:
1.12 rillig 158: // After calling fix.Apply above, the autofix is ready to be used again.
1.1 rillig 159: fix.Warnf("Use Y instead of X.")
160: fix.Replace("X", "Y")
161: fix.Apply()
162:
1.3 rillig 163: t.CheckOutputLines(
164: "AUTOFIX: ~/Makefile:2: Replacing \"X\" with \"Y\".",
165: "-\tline2",
166: "+\tYXXe2")
167:
1.1 rillig 168: SaveAutofixChanges(lines)
169:
1.2 rillig 170: t.CheckFileLines("Makefile",
171: "line1",
1.3 rillig 172: "YXXe2",
1.2 rillig 173: "line3")
1.1 rillig 174: }
175:
1.11 rillig 176: func (s *Suite) Test_Autofix_ReplaceRegex__show_autofix_and_source(c *check.C) {
1.2 rillig 177: t := s.Init(c)
178:
1.16 rillig 179: t.SetUpCommandLine("--show-autofix", "--source")
180: lines := t.SetUpFileLines("Makefile",
1.2 rillig 181: "line1",
182: "line2",
183: "line3")
1.1 rillig 184:
1.12 rillig 185: fix := lines.Lines[1].Autofix()
1.1 rillig 186: fix.Warnf("Something's wrong here.")
1.3 rillig 187: fix.ReplaceRegex(`.`, "X", -1)
1.1 rillig 188: fix.Apply()
189:
190: fix.Warnf("Use Y instead of X.")
191: fix.Replace("X", "Y")
192: fix.Apply()
193:
194: SaveAutofixChanges(lines)
195:
1.2 rillig 196: t.CheckOutputLines(
1.1 rillig 197: "WARN: ~/Makefile:2: Something's wrong here.",
1.3 rillig 198: "AUTOFIX: ~/Makefile:2: Replacing \"l\" with \"X\".",
199: "AUTOFIX: ~/Makefile:2: Replacing \"i\" with \"X\".",
200: "AUTOFIX: ~/Makefile:2: Replacing \"n\" with \"X\".",
201: "AUTOFIX: ~/Makefile:2: Replacing \"e\" with \"X\".",
202: "AUTOFIX: ~/Makefile:2: Replacing \"2\" with \"X\".",
1.2 rillig 203: "-\tline2",
204: "+\tXXXXX",
1.1 rillig 205: "",
206: "WARN: ~/Makefile:2: Use Y instead of X.",
207: "AUTOFIX: ~/Makefile:2: Replacing \"X\" with \"Y\".",
1.2 rillig 208: "-\tline2",
209: "+\tYXXXX")
1.1 rillig 210: }
211:
1.18 rillig 212: // When an autofix replaces text, it does not touch those
213: // lines that have been inserted before since these are
214: // usually already correct.
215: func (s *Suite) Test_Autofix_ReplaceAfter__after_inserting_a_line(c *check.C) {
216: t := s.Init(c)
217:
218: t.SetUpCommandLine("--show-autofix")
219: line := t.NewLine("filename", 5, "initial text")
220:
221: fix := line.Autofix()
222: fix.Notef("Inserting a line.")
223: fix.InsertBefore("line before")
224: fix.InsertAfter("line after")
225: fix.Apply()
226:
227: fix.Notef("Replacing text.")
228: fix.Replace("l", "L")
229: fix.ReplaceRegex(`i`, "I", 1)
230: fix.Apply()
231:
232: t.CheckOutputLines(
233: "NOTE: filename:5: Inserting a line.",
234: "AUTOFIX: filename:5: Inserting a line \"line before\" before this line.",
235: "AUTOFIX: filename:5: Inserting a line \"line after\" after this line.",
236: "NOTE: filename:5: Replacing text.",
237: "AUTOFIX: filename:5: Replacing \"l\" with \"L\".",
238: "AUTOFIX: filename:5: Replacing \"i\" with \"I\".")
239: }
240:
1.11 rillig 241: func (s *Suite) Test_SaveAutofixChanges(c *check.C) {
1.2 rillig 242: t := s.Init(c)
243:
1.16 rillig 244: t.SetUpCommandLine("--autofix")
245: lines := t.SetUpFileLines("example.txt",
1.2 rillig 246: "line1 := value1",
247: "line2 := value2",
248: "line3 := value3")
1.1 rillig 249:
1.12 rillig 250: fix := lines.Lines[1].Autofix()
1.1 rillig 251: fix.Warnf("Something's wrong here.")
1.12 rillig 252: fix.ReplaceRegex(`...`, "XXX", 2)
1.3 rillig 253: fix.Apply()
254:
1.12 rillig 255: SaveAutofixChanges(lines)
1.1 rillig 256:
1.3 rillig 257: t.CheckOutputLines(
1.12 rillig 258: "AUTOFIX: ~/example.txt:2: Replacing \"lin\" with \"XXX\".",
259: "AUTOFIX: ~/example.txt:2: Replacing \"e2 \" with \"XXX\".")
260: t.CheckFileLines("example.txt",
1.2 rillig 261: "line1 := value1",
1.12 rillig 262: "XXXXXX:= value2",
263: "line3 := value3")
1.1 rillig 264: }
265:
1.11 rillig 266: func (s *Suite) Test_SaveAutofixChanges__no_changes_necessary(c *check.C) {
267: t := s.Init(c)
268:
1.16 rillig 269: t.SetUpCommandLine("--autofix")
270: lines := t.SetUpFileLines("DESCR",
1.11 rillig 271: "Line 1",
272: "Line 2")
273:
1.12 rillig 274: fix := lines.Lines[0].Autofix()
1.11 rillig 275: fix.Warnf("Dummy warning.")
276: fix.Replace("X", "Y")
277: fix.Apply()
278:
279: // Since nothing has been effectively changed,
280: // nothing needs to be saved.
281: SaveAutofixChanges(lines)
282:
283: // And therefore, no AUTOFIX action must appear in the log.
284: t.CheckOutputEmpty()
285: }
286:
1.12 rillig 287: func (s *Suite) Test_Autofix__multiple_fixes(c *check.C) {
1.2 rillig 288: t := s.Init(c)
289:
1.16 rillig 290: t.SetUpCommandLine("--show-autofix", "--explain")
1.1 rillig 291:
1.13 rillig 292: line := t.NewLine("filename", 1, "original")
1.1 rillig 293:
294: c.Check(line.autofix, check.IsNil)
1.2 rillig 295: c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n"))
1.1 rillig 296:
297: {
298: fix := line.Autofix()
1.12 rillig 299: fix.Warnf(SilentAutofixFormat)
1.3 rillig 300: fix.ReplaceRegex(`(.)(.*)(.)`, "lriginao", 1) // XXX: the replacement should be "$3$2$1"
1.1 rillig 301: fix.Apply()
302: }
303:
304: c.Check(line.autofix, check.NotNil)
1.2 rillig 305: c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "lriginao\n"))
306: t.CheckOutputLines(
1.13 rillig 307: "AUTOFIX: filename:1: Replacing \"original\" with \"lriginao\".")
1.1 rillig 308:
309: {
310: fix := line.Autofix()
1.12 rillig 311: fix.Warnf(SilentAutofixFormat)
1.1 rillig 312: fix.Replace("i", "u")
313: fix.Apply()
314: }
315:
316: c.Check(line.autofix, check.NotNil)
1.2 rillig 317: c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "lruginao\n"))
1.1 rillig 318: c.Check(line.raw[0].textnl, equals, "lruginao\n")
1.2 rillig 319: t.CheckOutputLines(
1.13 rillig 320: "AUTOFIX: filename:1: Replacing \"i\" with \"u\".")
1.1 rillig 321:
322: {
323: fix := line.Autofix()
1.12 rillig 324: fix.Warnf(SilentAutofixFormat)
1.1 rillig 325: fix.Replace("lruginao", "middle")
326: fix.Apply()
327: }
328:
329: c.Check(line.autofix, check.NotNil)
1.2 rillig 330: c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "middle\n"))
1.1 rillig 331: c.Check(line.raw[0].textnl, equals, "middle\n")
1.2 rillig 332: t.CheckOutputLines(
1.13 rillig 333: "AUTOFIX: filename:1: Replacing \"lruginao\" with \"middle\".")
1.12 rillig 334:
335: c.Check(line.raw[0].textnl, equals, "middle\n")
336: t.CheckOutputEmpty()
1.1 rillig 337:
338: {
339: fix := line.Autofix()
1.12 rillig 340: fix.Warnf(SilentAutofixFormat)
341: fix.Delete()
1.1 rillig 342: fix.Apply()
1.12 rillig 343: }
344:
345: c.Check(line.Autofix().RawText(), equals, "")
346: t.CheckOutputLines(
1.13 rillig 347: "AUTOFIX: filename:1: Deleting this line.")
1.12 rillig 348: }
349:
350: func (s *Suite) Test_Autofix_Explain__without_explain_option(c *check.C) {
351: t := s.Init(c)
352:
353: line := t.NewLine("Makefile", 74, "line1")
1.1 rillig 354:
1.12 rillig 355: fix := line.Autofix()
356: fix.Warnf("Please write row instead of line.")
357: fix.Replace("line", "row")
358: fix.Explain("Explanation")
359: fix.Apply()
360:
361: t.CheckOutputLines(
362: "WARN: Makefile:74: Please write row instead of line.")
1.23 ! rillig 363: c.Check(G.Logger.explanationsAvailable, equals, true)
1.12 rillig 364: }
365:
366: func (s *Suite) Test_Autofix_Explain__default(c *check.C) {
367: t := s.Init(c)
368:
1.16 rillig 369: t.SetUpCommandLine("--explain")
1.12 rillig 370: line := t.NewLine("Makefile", 74, "line1")
371:
372: fix := line.Autofix()
373: fix.Warnf("Please write row instead of line.")
374: fix.Replace("line", "row")
375: fix.Explain("Explanation")
376: fix.Apply()
377:
378: t.CheckOutputLines(
379: "WARN: Makefile:74: Please write row instead of line.",
380: "",
381: "\tExplanation",
382: "")
1.23 ! rillig 383: c.Check(G.Logger.explanationsAvailable, equals, true)
1.12 rillig 384: }
385:
386: func (s *Suite) Test_Autofix_Explain__show_autofix(c *check.C) {
387: t := s.Init(c)
1.1 rillig 388:
1.16 rillig 389: t.SetUpCommandLine("--show-autofix", "--explain")
1.12 rillig 390: line := t.NewLine("Makefile", 74, "line1")
1.1 rillig 391:
1.12 rillig 392: fix := line.Autofix()
393: fix.Warnf("Please write row instead of line.")
394: fix.Replace("line", "row")
395: fix.Explain("Explanation")
396: fix.Apply()
1.1 rillig 397:
1.12 rillig 398: t.CheckOutputLines(
399: "WARN: Makefile:74: Please write row instead of line.",
400: "AUTOFIX: Makefile:74: Replacing \"line\" with \"row\".",
1.1 rillig 401: "",
1.12 rillig 402: "\tExplanation",
1.1 rillig 403: "")
1.23 ! rillig 404: c.Check(G.Logger.explanationsAvailable, equals, true)
1.12 rillig 405: }
406:
407: func (s *Suite) Test_Autofix_Explain__autofix(c *check.C) {
408: t := s.Init(c)
409:
1.16 rillig 410: t.SetUpCommandLine("--autofix", "--explain")
1.12 rillig 411: line := t.NewLine("Makefile", 74, "line1")
412:
413: fix := line.Autofix()
414: fix.Warnf("Please write row instead of line.")
415: fix.Replace("line", "row")
416: fix.Explain("Explanation")
417: fix.Apply()
1.1 rillig 418:
1.12 rillig 419: t.CheckOutputLines(
420: "AUTOFIX: Makefile:74: Replacing \"line\" with \"row\".")
1.23 ! rillig 421: c.Check(G.Logger.explanationsAvailable, equals, false) // Not necessary.
1.12 rillig 422: }
423:
424: func (s *Suite) Test_Autofix_Explain__SilentAutofixFormat(c *check.C) {
425: t := s.Init(c)
426:
1.16 rillig 427: t.SetUpCommandLine("--explain")
1.12 rillig 428: line := t.NewLine("example.txt", 1, "Text")
429:
430: fix := line.Autofix()
431: fix.Warnf(SilentAutofixFormat)
432: t.ExpectPanic(
433: func() { fix.Explain("Explanation for inserting a line before.") },
434: "Pkglint internal error: Autofix: Silent fixes cannot have an explanation.")
435: }
436:
437: // To combine a silent diagnostic with an explanation, two separate autofixes
438: // are necessary.
439: func (s *Suite) Test_Autofix_Explain__silent_with_diagnostic(c *check.C) {
440: t := s.Init(c)
441:
1.16 rillig 442: t.SetUpCommandLine("--explain")
1.12 rillig 443: line := t.NewLine("example.txt", 1, "Text")
444:
445: fix := line.Autofix()
446: fix.Warnf(SilentAutofixFormat)
447: fix.InsertBefore("before")
448: fix.Apply()
449:
450: fix.Notef("This diagnostic is necessary for the following explanation.")
451: fix.Explain(
452: "When inserting multiple lines, Apply must be called in-between.",
453: "Otherwise the changes are not described to the human reader.")
454: fix.InsertAfter("after")
455: fix.Apply()
1.1 rillig 456:
1.2 rillig 457: t.CheckOutputLines(
1.12 rillig 458: "NOTE: example.txt:1: This diagnostic is necessary for the following explanation.",
459: "",
460: "\tWhen inserting multiple lines, Apply must be called in-between.",
461: "\tOtherwise the changes are not described to the human reader.",
462: "")
463: c.Check(fix.RawText(), equals, "Text\n")
1.1 rillig 464: }
465:
1.12 rillig 466: func (s *Suite) Test_Autofix__show_autofix_and_source_continuation_line(c *check.C) {
1.2 rillig 467: t := s.Init(c)
468:
1.16 rillig 469: t.SetUpCommandLine("--show-autofix", "--source")
470: mklines := t.SetUpFileMkLines("Makefile",
1.4 rillig 471: MkRcsID,
1.9 rillig 472: "# before \\",
1.2 rillig 473: "The old song \\",
474: "after")
1.12 rillig 475: line := mklines.lines.Lines[1]
1.1 rillig 476:
1.13 rillig 477: fix := line.Autofix()
478: fix.Warnf("Using \"old\" is deprecated.")
479: fix.Replace("old", "new")
480: fix.Apply()
1.1 rillig 481:
1.13 rillig 482: // Using a tab for indentation preserves the exact layout in the output
483: // since in pkgsrc Makefiles, tabs are also used in the middle of the line
484: // to align the variable values. Using a single space for indentation would
485: // make some of the lines appear misaligned in the pkglint output although
486: // they are correct in the Makefiles.
1.2 rillig 487: t.CheckOutputLines(
488: "WARN: ~/Makefile:2--4: Using \"old\" is deprecated.",
489: "AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".",
1.13 rillig 490: "\t# before \\",
1.2 rillig 491: "-\tThe old song \\",
492: "+\tThe new song \\",
1.13 rillig 493: "\tafter")
1.1 rillig 494: }
495:
496: func (s *Suite) Test_Autofix_InsertBefore(c *check.C) {
1.2 rillig 497: t := s.Init(c)
498:
1.16 rillig 499: t.SetUpCommandLine("--show-autofix", "--source")
1.2 rillig 500: line := t.NewLine("Makefile", 30, "original")
1.1 rillig 501:
502: fix := line.Autofix()
1.6 rillig 503: fix.Warnf("Dummy.")
1.1 rillig 504: fix.InsertBefore("inserted")
505: fix.Apply()
506:
1.2 rillig 507: t.CheckOutputLines(
1.6 rillig 508: "WARN: Makefile:30: Dummy.",
1.1 rillig 509: "AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.",
1.2 rillig 510: "+\tinserted",
511: ">\toriginal")
1.1 rillig 512: }
513:
514: func (s *Suite) Test_Autofix_Delete(c *check.C) {
1.2 rillig 515: t := s.Init(c)
516:
1.16 rillig 517: t.SetUpCommandLine("--show-autofix", "--source")
1.2 rillig 518: line := t.NewLine("Makefile", 30, "to be deleted")
1.1 rillig 519:
520: fix := line.Autofix()
1.6 rillig 521: fix.Warnf("Dummy.")
1.1 rillig 522: fix.Delete()
523: fix.Apply()
524:
1.2 rillig 525: t.CheckOutputLines(
1.6 rillig 526: "WARN: Makefile:30: Dummy.",
1.1 rillig 527: "AUTOFIX: Makefile:30: Deleting this line.",
1.2 rillig 528: "-\tto be deleted")
1.1 rillig 529: }
530:
1.12 rillig 531: // Deleting a line from a Makefile also deletes its continuation lines.
532: func (s *Suite) Test_Autofix_Delete__continuation_line(c *check.C) {
533: t := s.Init(c)
534:
1.16 rillig 535: t.SetUpCommandLine("--show-autofix", "--source")
536: mklines := t.SetUpFileMkLines("Makefile",
1.12 rillig 537: MkRcsID,
538: "# line 1 \\",
539: "continued")
540: line := mklines.lines.Lines[1]
541:
542: fix := line.Autofix()
543: fix.Warnf("Dummy warning.")
544: fix.Delete()
545: fix.Apply()
546:
547: t.CheckOutputLines(
548: "WARN: ~/Makefile:2--3: Dummy warning.",
549: "AUTOFIX: ~/Makefile:2: Deleting this line.",
550: "AUTOFIX: ~/Makefile:3: Deleting this line.",
551: "-\t# line 1 \\",
552: "-\tcontinued")
553: }
554:
555: func (s *Suite) Test_Autofix_Delete__combined_with_insert(c *check.C) {
556: t := s.Init(c)
557:
1.16 rillig 558: t.SetUpCommandLine("--show-autofix", "--source")
1.12 rillig 559: line := t.NewLine("Makefile", 30, "to be deleted")
560:
561: fix := line.Autofix()
562: fix.Warnf("This line should be replaced completely.")
563: fix.Delete()
564: fix.InsertAfter("below")
565: fix.InsertBefore("above")
566: fix.Apply()
567:
568: t.CheckOutputLines(
569: "WARN: Makefile:30: This line should be replaced completely.",
570: "AUTOFIX: Makefile:30: Deleting this line.",
571: "AUTOFIX: Makefile:30: Inserting a line \"below\" after this line.",
572: "AUTOFIX: Makefile:30: Inserting a line \"above\" before this line.",
573: "+\tabove",
574: "-\tto be deleted",
575: "+\tbelow")
576: }
577:
1.17 rillig 578: // Demonstrates that without the --show-autofix option, diagnostics are
579: // shown even when they cannot be autofixed.
580: //
581: // This is typical when an autofix is provided for simple scenarios,
582: // but the code actually found is a little more complicated.
583: func (s *Suite) Test_Autofix__show_unfixable_diagnostics_in_default_mode(c *check.C) {
584: t := s.Init(c)
585:
586: t.SetUpCommandLine("--source")
587: lines := t.NewLines("Makefile",
588: "line1",
589: "line2",
590: "line3")
591:
592: lines.Lines[0].Warnf("This warning is shown since the --show-autofix option is not given.")
593:
594: fix := lines.Lines[1].Autofix()
595: fix.Warnf("This warning cannot be fixed and is therefore not shown.")
596: fix.Replace("XXX", "TODO")
597: fix.Apply()
598:
599: fix.Warnf("This warning cannot be fixed automatically but should be shown anyway.")
600: fix.Replace("XXX", "TODO")
601: fix.Anyway()
602: fix.Apply()
603:
604: // If this warning should ever appear it is probably because fix.anyway is not reset properly.
605: fix.Warnf("This warning cannot be fixed and is therefore not shown.")
606: fix.Replace("XXX", "TODO")
607: fix.Apply()
608:
609: lines.Lines[2].Warnf("This warning is also shown.")
610:
611: t.CheckOutputLines(
612: ">\tline1",
613: "WARN: Makefile:1: This warning is shown since the --show-autofix option is not given.",
614: "",
615: ">\tline2",
616: "WARN: Makefile:2: This warning cannot be fixed automatically but should be shown anyway.",
617: "",
618: ">\tline3",
619: "WARN: Makefile:3: This warning is also shown.")
620: }
621:
1.1 rillig 622: // Demonstrates that the --show-autofix option only shows those diagnostics
623: // that would be fixed.
1.17 rillig 624: func (s *Suite) Test_Autofix__suppress_unfixable_warnings_with_show_autofix(c *check.C) {
1.2 rillig 625: t := s.Init(c)
626:
1.16 rillig 627: t.SetUpCommandLine("--show-autofix", "--source")
1.2 rillig 628: lines := t.NewLines("Makefile",
1.1 rillig 629: "line1",
630: "line2",
631: "line3")
632:
1.12 rillig 633: lines.Lines[0].Warnf("This warning is not shown since it is not part of a fix.")
1.1 rillig 634:
1.12 rillig 635: fix := lines.Lines[1].Autofix()
1.1 rillig 636: fix.Warnf("Something's wrong here.")
1.12 rillig 637: fix.ReplaceRegex(`.....`, "XXX", 1)
1.1 rillig 638: fix.Apply()
639:
1.11 rillig 640: fix.Warnf("Since XXX marks are usually not fixed, use TODO instead to draw attention.")
1.1 rillig 641: fix.Replace("XXX", "TODO")
642: fix.Apply()
643:
1.12 rillig 644: lines.Lines[2].Warnf("Neither is this warning shown.")
1.1 rillig 645:
1.2 rillig 646: t.CheckOutputLines(
1.1 rillig 647: "WARN: Makefile:2: Something's wrong here.",
1.12 rillig 648: "AUTOFIX: Makefile:2: Replacing \"line2\" with \"XXX\".",
1.2 rillig 649: "-\tline2",
1.12 rillig 650: "+\tXXX",
1.1 rillig 651: "",
1.11 rillig 652: "WARN: Makefile:2: Since XXX marks are usually not fixed, use TODO instead to draw attention.",
1.1 rillig 653: "AUTOFIX: Makefile:2: Replacing \"XXX\" with \"TODO\".",
1.2 rillig 654: "-\tline2",
1.12 rillig 655: "+\tTODO")
1.2 rillig 656: }
657:
1.18 rillig 658: // With the default command line options, this warning is printed.
659: // With the --show-autofix option this warning is NOT printed since it
660: // cannot be fixed automatically.
661: func (s *Suite) Test_Autofix_Anyway__options(c *check.C) {
662: t := s.Init(c)
663:
664: t.SetUpCommandLine("--show-autofix")
665:
666: line := t.NewLine("filename", 3, "")
667: fix := line.Autofix()
668:
669: fix.Warnf("This autofix doesn't match.")
670: fix.Replace("doesn't match", "")
671: fix.Anyway()
672: fix.Apply()
673:
674: t.CheckOutputEmpty()
675:
676: t.SetUpCommandLine()
677:
678: fix.Warnf("This autofix doesn't match.")
679: fix.Replace("doesn't match", "")
680: fix.Anyway()
681: fix.Apply()
682:
683: t.CheckOutputLines(
684: "WARN: filename:3: This autofix doesn't match.")
685: }
686:
1.12 rillig 687: // If an Autofix doesn't do anything, it must not log any diagnostics.
1.11 rillig 688: func (s *Suite) Test_Autofix__noop_replace(c *check.C) {
1.2 rillig 689: t := s.Init(c)
690:
691: line := t.NewLine("Makefile", 14, "Original text")
692:
693: fix := line.Autofix()
694: fix.Warnf("All-uppercase words should not be used at all.")
1.3 rillig 695: fix.ReplaceRegex(`\b[A-Z]{3,}\b`, "---censored---", -1)
1.2 rillig 696: fix.Apply()
697:
698: // No output since there was no all-uppercase word in the text.
699: t.CheckOutputEmpty()
1.1 rillig 700: }
701:
1.12 rillig 702: // When using Autofix.Custom, it is tricky to get all the details right.
1.11 rillig 703: // For best results, see the existing examples and the documentation.
1.12 rillig 704: //
705: // Since this custom fix only operates on the text of the current line,
706: // it can handle both the --show-autofix and the --autofix cases using
707: // the same code.
708: func (s *Suite) Test_Autofix_Custom__in_memory(c *check.C) {
1.5 rillig 709: t := s.Init(c)
710:
711: lines := t.NewLines("Makefile",
712: "line1",
713: "line2",
714: "line3")
715:
716: doFix := func(line Line) {
717: fix := line.Autofix()
1.6 rillig 718: fix.Warnf("Please write in ALL-UPPERCASE.")
1.12 rillig 719: fix.Custom(func(showAutofix, autofix bool) {
1.5 rillig 720: fix.Describef(int(line.firstLine), "Converting to uppercase")
1.12 rillig 721: if showAutofix || autofix {
1.5 rillig 722: line.Text = strings.ToUpper(line.Text)
723: }
724: })
725: fix.Apply()
726: }
727:
1.12 rillig 728: doFix(lines.Lines[0])
1.5 rillig 729:
730: t.CheckOutputLines(
1.6 rillig 731: "WARN: Makefile:1: Please write in ALL-UPPERCASE.")
1.5 rillig 732:
1.16 rillig 733: t.SetUpCommandLine("--show-autofix")
1.5 rillig 734:
1.12 rillig 735: doFix(lines.Lines[1])
1.5 rillig 736:
737: t.CheckOutputLines(
1.6 rillig 738: "WARN: Makefile:2: Please write in ALL-UPPERCASE.",
1.5 rillig 739: "AUTOFIX: Makefile:2: Converting to uppercase")
1.12 rillig 740: c.Check(lines.Lines[1].Text, equals, "LINE2")
1.5 rillig 741:
1.16 rillig 742: t.SetUpCommandLine("--autofix")
1.5 rillig 743:
1.12 rillig 744: doFix(lines.Lines[2])
1.5 rillig 745:
746: t.CheckOutputLines(
747: "AUTOFIX: Makefile:3: Converting to uppercase")
1.12 rillig 748: c.Check(lines.Lines[2].Text, equals, "LINE3")
1.6 rillig 749: }
1.8 rillig 750:
751: // Since the diagnostic doesn't contain the string "few", nothing happens.
1.12 rillig 752: func (s *Suite) Test_Autofix_skip(c *check.C) {
1.8 rillig 753: t := s.Init(c)
754:
1.16 rillig 755: t.SetUpCommandLine("--only", "few", "--autofix")
1.8 rillig 756:
1.16 rillig 757: mklines := t.SetUpFileMkLines("filename",
1.12 rillig 758: "VAR=\t111 222 333 444 555 \\",
759: "666")
760: lines := mklines.lines
1.8 rillig 761:
1.12 rillig 762: fix := lines.Lines[0].Autofix()
1.8 rillig 763: fix.Warnf("Many.")
764: fix.Explain(
765: "Explanation.")
1.12 rillig 766:
767: // None of the following actions has any effect because of the --only option above.
1.8 rillig 768: fix.Replace("111", "___")
769: fix.ReplaceAfter(" ", "222", "___")
770: fix.ReplaceRegex(`\d+`, "___", 1)
771: fix.InsertBefore("before")
772: fix.InsertAfter("after")
773: fix.Delete()
1.12 rillig 774: fix.Custom(func(showAutofix, autofix bool) {})
775: fix.Realign(mklines.mklines[0], 32)
776:
1.8 rillig 777: fix.Apply()
778:
779: SaveAutofixChanges(lines)
780:
781: t.CheckOutputEmpty()
1.13 rillig 782: t.CheckFileLines("filename",
1.12 rillig 783: "VAR=\t111 222 333 444 555 \\",
784: "666")
785: c.Check(fix.RawText(), equals, ""+
786: "VAR=\t111 222 333 444 555 \\\n"+
787: "666\n")
788: }
789:
790: // Demonstrates how to filter log messages.
791: // The --autofix option can restrict the fixes to exactly one group or topic.
792: func (s *Suite) Test_Autofix_Apply__only(c *check.C) {
793: t := s.Init(c)
794:
1.16 rillig 795: t.SetUpCommandLine("--autofix", "--source", "--only", "interesting")
1.12 rillig 796: line := t.NewLine("Makefile", 27, "The old song")
797:
798: // Is completely ignored, including any autofixes.
799: fix := line.Autofix()
800: fix.Warnf("Using \"old\" is deprecated.")
801: fix.Replace("old", "new1")
802: fix.Apply()
803:
804: fix.Warnf("Using \"old\" is interesting.")
805: fix.Replace("old", "new2")
806: fix.Apply()
807:
808: t.CheckOutputLines(
809: "AUTOFIX: Makefile:27: Replacing \"old\" with \"new2\".",
810: "-\tThe old song",
811: "+\tThe new2 song")
1.8 rillig 812: }
1.10 rillig 813:
814: func (s *Suite) Test_Autofix_Apply__panic(c *check.C) {
815: t := s.Init(c)
816:
1.13 rillig 817: line := t.NewLine("filename", 123, "text")
1.12 rillig 818:
819: t.ExpectPanic(
820: func() {
821: fix := line.Autofix()
822: fix.Apply()
823: },
824: "Pkglint internal error: Each autofix must have a log level and a diagnostic.")
825:
826: t.ExpectPanic(
827: func() {
828: fix := line.Autofix()
829: fix.Replace("from", "to")
830: fix.Apply()
831: },
832: "Pkglint internal error: Autofix: The diagnostic must be given before the action.")
833:
834: t.ExpectPanic(
835: func() {
836: fix := line.Autofix()
837: fix.Warnf("Warning without period")
838: fix.Apply()
839: },
840: "Pkglint internal error: Autofix: format \"Warning without period\" must end with a period.")
841: }
1.10 rillig 842:
1.12 rillig 843: // Ensures that empty lines are logged between the diagnostics,
844: // even when combining normal warnings and autofix warnings.
845: //
846: // Up to 2018-10-27, pkglint didn't insert the required empty line in this case.
847: func (s *Suite) Test_Autofix_Apply__explanation_followed_by_note(c *check.C) {
848: t := s.Init(c)
849:
1.16 rillig 850: t.SetUpCommandLine("--source")
1.12 rillig 851: line := t.NewLine("README.txt", 123, "text")
852:
853: fix := line.Autofix()
854: fix.Warnf("A warning with autofix.")
855: fix.Explain("Explanation.")
856: fix.Replace("text", "Text")
857: fix.Apply()
1.10 rillig 858:
1.12 rillig 859: line.Notef("A note without fix.")
1.10 rillig 860:
1.12 rillig 861: t.CheckOutputLines(
862: ">\ttext",
863: "WARN: README.txt:123: A warning with autofix.",
864: "",
865: ">\ttext",
866: "NOTE: README.txt:123: A note without fix.")
1.10 rillig 867: }
868:
1.18 rillig 869: func (s *Suite) Test_Autofix_Anyway__autofix_option(c *check.C) {
870: t := s.Init(c)
871:
872: t.SetUpCommandLine("--autofix")
873: line := t.NewLine("filename", 5, "text")
874:
875: fix := line.Autofix()
876: fix.Notef("This line is quite short.")
877: fix.Replace("not found", "needle")
878: fix.Anyway()
879: fix.Apply()
880:
881: // The replacement text is not found, therefore the note should not be logged.
882: // Because of fix.Anyway, the note should be logged anyway.
883: // But because of the --autofix option, the note should not be logged.
884: // Therefore, in the end nothing is shown in this case.
885: t.CheckOutputEmpty()
886: }
887:
888: func (s *Suite) Test_Autofix_Anyway__autofix_and_show_autofix_options(c *check.C) {
889: t := s.Init(c)
890:
891: t.SetUpCommandLine("--autofix", "--show-autofix")
892: line := t.NewLine("filename", 5, "text")
893:
894: fix := line.Autofix()
895: fix.Notef("This line is quite short.")
896: fix.Replace("not found", "needle")
897: fix.Anyway()
898: fix.Apply()
899:
1.21 rillig 900: // The text to be replaced is not found. Because nothing is fixed here,
901: // there's no need to log anything.
902: //
903: // But fix.Anyway is set, therefore the diagnostic should be logged even
904: // though it cannot be fixed automatically. This comes handy in situations
905: // where simple cases can be fixed automatically and more complex cases
906: // (often involving special characters that need to be escaped properly)
907: // should nevertheless result in a diagnostics.
908: //
909: // The --autofix option is set, which means that the diagnostics don't
910: // get logged, only the actual fixes do.
911: //
912: // But then there's also the --show-autofix option, which logs the
913: // corresponding diagnostic for each autofix that actually changes
914: // something. But this autofix doesn't change anything, therefore even
915: // the --show-autofix doesn't have an effect.
916: //
917: // Therefore, in the end nothing is logged in this case.
1.18 rillig 918: t.CheckOutputEmpty()
919: }
920:
921: // The --autofix option normally suppresses the diagnostics and just logs
922: // the actual fixes. Adding the --show-autofix option logs both.
923: func (s *Suite) Test_Autofix_Apply__autofix_and_show_autofix_options(c *check.C) {
924: t := s.Init(c)
925:
926: t.SetUpCommandLine("--autofix", "--show-autofix")
927: line := t.NewLine("filename", 5, "text")
928:
929: fix := line.Autofix()
930: fix.Notef("This line is quite short.")
931: fix.Replace("text", "replacement")
932: fix.Apply()
933:
934: t.CheckOutputLines(
935: "NOTE: filename:5: This line is quite short.",
936: "AUTOFIX: filename:5: Replacing \"text\" with \"replacement\".")
937: }
938:
939: // Ensures that without explanations, the separator between the individual
940: // diagnostics are generated.
941: func (s *Suite) Test_Autofix_Apply__source_without_explain(c *check.C) {
942: t := s.Init(c)
943:
944: t.SetUpCommandLine("--source", "--explain", "--show-autofix")
945: line := t.NewLine("filename", 5, "text")
946:
947: fix := line.Autofix()
948: fix.Notef("This line is quite short.")
949: fix.Replace("text", "replacement")
950: fix.Apply()
951:
952: fix.Warnf("Follow-up warning, separated.")
953: fix.Replace("replacement", "text again")
954: fix.Apply()
955:
956: t.CheckOutputLines(
957: "NOTE: filename:5: This line is quite short.",
958: "AUTOFIX: filename:5: Replacing \"text\" with \"replacement\".",
959: "-\ttext",
960: "+\treplacement",
961: "",
962: "WARN: filename:5: Follow-up warning, separated.",
963: "AUTOFIX: filename:5: Replacing \"replacement\" with \"text again\".",
964: "-\ttext",
965: "+\ttext again")
966: }
967:
968: func (s *Suite) Test_Autofix_Realign__wrong_line_type(c *check.C) {
969: t := s.Init(c)
970:
971: mklines := t.NewMkLines("file.mk",
972: MkRcsID,
973: ".if \\",
974: "${PKGSRC_RUN_TESTS}")
975:
976: mkline := mklines.mklines[1]
977: fix := mkline.Autofix()
978:
979: t.ExpectPanic(
980: func() { fix.Realign(mkline, 16) },
981: "Pkglint internal error: Line must be a variable assignment.")
982: }
983:
984: func (s *Suite) Test_Autofix_Realign__short_continuation_line(c *check.C) {
985: t := s.Init(c)
986:
987: t.SetUpCommandLine("--autofix")
988: mklines := t.SetUpFileMkLines("file.mk",
989: MkRcsID,
990: "BUILD_DIRS= \\",
991: "\tdir \\",
992: "")
993: mkline := mklines.mklines[1]
994: fix := mkline.Autofix()
995: fix.Warnf("Line should be realigned.")
996:
997: // In this case realigning has no effect since the oldWidth == 8,
998: // which counts as "sufficiently intentional not to be modified".
999: fix.Realign(mkline, 16)
1000:
1001: mklines.SaveAutofixChanges()
1002:
1003: t.CheckOutputEmpty()
1004: t.CheckFileLines("file.mk",
1005: MkRcsID,
1006: "BUILD_DIRS= \\",
1007: "\tdir \\",
1008: "")
1009: }
1010:
1011: func (s *Suite) Test_Autofix_Realign__multiline_indented_with_spaces(c *check.C) {
1012: t := s.Init(c)
1013:
1014: t.SetUpCommandLine("--autofix")
1015: mklines := t.SetUpFileMkLines("file.mk",
1016: MkRcsID,
1017: "BUILD_DIRS= \\",
1018: "\t dir1 \\",
1019: "\t\tdir2 \\",
1020: " ") // Trailing whitespace is not fixed by Autofix.Realign.
1021:
1022: mkline := mklines.mklines[1]
1023:
1024: fix := mkline.Autofix()
1025: fix.Warnf("Warning.")
1026: fix.Realign(mkline, 16)
1027: fix.Apply()
1028:
1029: mklines.SaveAutofixChanges()
1030:
1031: t.CheckOutputLines(
1032: "AUTOFIX: ~/file.mk:3: Replacing indentation \"\\t \" with \"\\t\\t\".")
1033: t.CheckFileLines("file.mk",
1034: MkRcsID,
1035: "BUILD_DIRS= \\",
1036: "\t\tdir1 \\",
1037: "\t\tdir2 \\",
1038: " ")
1039: }
1040:
1041: // Just for branch coverage.
1042: func (s *Suite) Test_Autofix_setDiag__no_testing_mode(c *check.C) {
1043: t := s.Init(c)
1044:
1045: line := t.NewLine("file.mk", 123, "text")
1046:
1047: G.Testing = false
1048:
1049: fix := line.Autofix()
1050: fix.Notef("Note.")
1051: fix.Replace("from", "to")
1052: fix.Apply()
1053:
1054: t.CheckOutputEmpty()
1055: }
1056:
1057: func (s *Suite) Test_Autofix_setDiag__bad_call_sequence(c *check.C) {
1058: t := s.Init(c)
1059:
1060: line := t.NewLine("file.mk", 123, "text")
1061: fix := line.Autofix()
1062: fix.Notef("Note.")
1063:
1064: t.ExpectPanic(
1065: func() { fix.Notef("Note 2.") },
1066: "Pkglint internal error: Autofix can only have a single diagnostic.")
1067:
1068: fix.level = nil // To cover the second assertion.
1069: t.ExpectPanic(
1070: func() { fix.Notef("Note 2.") },
1071: "Pkglint internal error: Autofix can only have a single diagnostic.")
1072: }
1073:
1074: func (s *Suite) Test_Autofix_assertRealLine(c *check.C) {
1075: t := s.Init(c)
1076:
1077: line := NewLineEOF("filename.mk")
1078: fix := line.Autofix()
1079: fix.Warnf("Warning.")
1080:
1081: t.ExpectPanic(
1082: func() { fix.Replace("from", "to") },
1083: "Pkglint internal error: Cannot autofix this line since it is not a real line.")
1084: }
1085:
1.12 rillig 1086: func (s *Suite) Test_SaveAutofixChanges__file_removed(c *check.C) {
1.10 rillig 1087: t := s.Init(c)
1088:
1.16 rillig 1089: t.SetUpCommandLine("--autofix")
1090: lines := t.SetUpFileLines("subdir/file.txt",
1.10 rillig 1091: "line 1")
1.12 rillig 1092: _ = os.RemoveAll(t.File("subdir"))
1.10 rillig 1093:
1.12 rillig 1094: fix := lines.Lines[0].Autofix()
1.10 rillig 1095: fix.Warnf("Should start with an uppercase letter.")
1096: fix.Replace("line", "Line")
1097: fix.Apply()
1098:
1099: SaveAutofixChanges(lines)
1100:
1.22 rillig 1101: t.CheckOutputMatches(
1102: "AUTOFIX: ~/subdir/file.txt:1: Replacing \"line\" with \"Line\".",
1103: `ERROR: ~/subdir/file.txt.pkglint.tmp: Cannot write: .*`)
1.10 rillig 1104: }
1105:
1.12 rillig 1106: func (s *Suite) Test_SaveAutofixChanges__file_busy_Windows(c *check.C) {
1.10 rillig 1107: t := s.Init(c)
1108:
1109: if runtime.GOOS != "windows" {
1110: return
1111: }
1112:
1.16 rillig 1113: t.SetUpCommandLine("--autofix")
1114: lines := t.SetUpFileLines("subdir/file.txt",
1.10 rillig 1115: "line 1")
1116:
1117: // As long as the file is kept open, it cannot be overwritten or deleted.
1118: openFile, err := os.OpenFile(t.File("subdir/file.txt"), 0, 0666)
1119: defer openFile.Close()
1120: c.Check(err, check.IsNil)
1121:
1.12 rillig 1122: fix := lines.Lines[0].Autofix()
1.10 rillig 1123: fix.Warnf("Should start with an uppercase letter.")
1124: fix.Replace("line", "Line")
1125: fix.Apply()
1126:
1127: SaveAutofixChanges(lines)
1128:
1.22 rillig 1129: t.CheckOutputMatches(
1130: "AUTOFIX: ~/subdir/file.txt:1: Replacing \"line\" with \"Line\".",
1131: `ERROR: ~/subdir/file.txt.pkglint.tmp: Cannot overwrite with autofixed content: .*`)
1.10 rillig 1132: }
1133:
1.12 rillig 1134: // This test covers the highly unlikely situation in which a file is loaded
1.10 rillig 1135: // by pkglint, and just before writing the autofixed content back, another
1136: // process takes the file and replaces it with a directory of the same name.
1137: //
1138: // 100% code coverage sometimes requires creativity. :)
1.12 rillig 1139: func (s *Suite) Test_SaveAutofixChanges__cannot_overwrite(c *check.C) {
1.10 rillig 1140: t := s.Init(c)
1141:
1.16 rillig 1142: t.SetUpCommandLine("--autofix")
1143: lines := t.SetUpFileLines("file.txt",
1.10 rillig 1144: "line 1")
1145:
1146: c.Check(os.RemoveAll(t.File("file.txt")), check.IsNil)
1147: c.Check(os.MkdirAll(t.File("file.txt"), 0777), check.IsNil)
1148:
1.12 rillig 1149: fix := lines.Lines[0].Autofix()
1.10 rillig 1150: fix.Warnf("Should start with an uppercase letter.")
1151: fix.Replace("line", "Line")
1152: fix.Apply()
1153:
1154: SaveAutofixChanges(lines)
1155:
1.22 rillig 1156: t.CheckOutputMatches(
1157: "AUTOFIX: ~/file.txt:1: Replacing \"line\" with \"Line\".",
1158: `ERROR: ~/file.txt.pkglint.tmp: Cannot overwrite with autofixed content: .*`)
1.12 rillig 1159: }
1160:
1.13 rillig 1161: // Up to 2018-11-25, pkglint in some cases logged only the source without
1162: // a corresponding warning.
1163: func (s *Suite) Test_Autofix__lonely_source(c *check.C) {
1164: t := s.Init(c)
1165:
1.16 rillig 1166: t.SetUpCommandLine("-Wall", "--source")
1.13 rillig 1167: G.Logger.Opts.LogVerbose = false // For realistic conditions; otherwise all diagnostics are logged.
1168:
1.16 rillig 1169: t.SetUpPackage("x11/xorg-cf-files",
1.13 rillig 1170: ".include \"../../x11/xorgproto/buildlink3.mk\"")
1.16 rillig 1171: t.SetUpPackage("x11/xorgproto",
1.13 rillig 1172: "DISTNAME=\txorgproto-1.0")
1173: t.CreateFileDummyBuildlink3("x11/xorgproto/buildlink3.mk")
1174: t.CreateFileLines("x11/xorgproto/builtin.mk",
1175: MkRcsID,
1176: "",
1177: "BUILTIN_PKG:=\txorgproto",
1178: "",
1179: "PRE_XORGPROTO_LIST_MISSING =\tapplewmproto",
1180: "",
1181: ".for id in ${PRE_XORGPROTO_LIST_MISSING}",
1182: ".endfor")
1183: t.Chdir(".")
1.20 rillig 1184: t.FinishSetUp()
1.13 rillig 1185:
1.15 rillig 1186: G.Check("x11/xorg-cf-files")
1187: G.Check("x11/xorgproto")
1.13 rillig 1188:
1189: t.CheckOutputLines(
1190: ">\tPRE_XORGPROTO_LIST_MISSING =\tapplewmproto",
1191: "NOTE: x11/xorgproto/builtin.mk:5: Unnecessary space after variable name \"PRE_XORGPROTO_LIST_MISSING\".")
1192: }
1193:
1194: // Up to 2018-11-26, pkglint in some cases logged only the source without
1195: // a corresponding warning.
1196: func (s *Suite) Test_Autofix__lonely_source_2(c *check.C) {
1197: t := s.Init(c)
1198:
1.16 rillig 1199: t.SetUpCommandLine("-Wall", "--source", "--explain")
1.13 rillig 1200: G.Logger.Opts.LogVerbose = false // For realistic conditions; otherwise all diagnostics are logged.
1201:
1.16 rillig 1202: t.SetUpPackage("print/tex-bibtex8",
1.13 rillig 1203: "MAKE_FLAGS+=\tCFLAGS=${CFLAGS.${PKGSRC_COMPILER}}")
1204: t.Chdir(".")
1.20 rillig 1205: t.FinishSetUp()
1.13 rillig 1206:
1.15 rillig 1207: G.Check("print/tex-bibtex8")
1.13 rillig 1208:
1209: t.CheckOutputLines(
1210: ">\tMAKE_FLAGS+=\tCFLAGS=${CFLAGS.${PKGSRC_COMPILER}}",
1211: "WARN: print/tex-bibtex8/Makefile:20: Please use ${CFLAGS.${PKGSRC_COMPILER}:Q} instead of ${CFLAGS.${PKGSRC_COMPILER}}.",
1212: "",
1213: "\tSee the pkgsrc guide, section \"Echoing a string exactly as-is\":",
1214: "\thttps://www.NetBSD.org/docs/pkgsrc/pkgsrc.html#echo-literal",
1215: "",
1216: ">\tMAKE_FLAGS+=\tCFLAGS=${CFLAGS.${PKGSRC_COMPILER}}",
1217: "WARN: print/tex-bibtex8/Makefile:20: The list variable PKGSRC_COMPILER should not be embedded in a word.",
1218: "",
1219: "\tWhen a list variable has multiple elements, this expression expands",
1220: "\tto something unexpected:",
1221: "",
1222: "\tExample: ${MASTER_SITE_SOURCEFORGE}directory/ expands to",
1223: "",
1224: "\t\thttps://mirror1.sf.net/ https://mirror2.sf.net/directory/",
1225: "",
1.14 rillig 1226: "\tThe first URL is missing the directory. To fix this, write",
1.13 rillig 1227: "\t\t${MASTER_SITE_SOURCEFORGE:=directory/}.",
1228: "",
1229: "\tExample: -l${LIBS} expands to",
1230: "",
1231: "\t\t-llib1 lib2",
1232: "",
1.14 rillig 1233: "\tThe second library is missing the -l. To fix this, write",
1234: "\t${LIBS:S,^,-l,}.",
1.13 rillig 1235: "")
1236: }
1237:
1.12 rillig 1238: // RawText returns the raw text of the fixed line, including line ends.
1239: // This may differ from the original text when the --show-autofix
1240: // or --autofix options are enabled.
1241: func (fix *Autofix) RawText() string {
1242: var text strings.Builder
1243: for _, lineBefore := range fix.linesBefore {
1244: text.WriteString(lineBefore)
1245: }
1246: for _, raw := range fix.line.raw {
1247: text.WriteString(raw.textnl)
1248: }
1249: for _, lineAfter := range fix.linesAfter {
1250: text.WriteString(lineAfter)
1251: }
1252: return text.String()
1.10 rillig 1253: }
CVSweb <webmaster@jp.NetBSD.org>