Can cause issues on Windows consider filepath.Join instead
ignoreFileName := filepath.Join(tmpDir, ".gitignore")
1package main23import (4 "fmt"5 "os"6 "os/exec"7 "path/filepath"8 "regexp"9 "runtime"10 "slices"11 "strconv"12 "strings"13 "testing"14)1516const sccTestFlag string = "-test.main"1718var sccBinPath = os.Args[0]1920func TestMain(m *testing.M) {21 idx := slices.Index(os.Args, sccTestFlag)22 if idx != -1 {23 os.Args = slices.Delete(os.Args, idx, idx+1)24 main()25 return26 }2728 os.Exit(m.Run())29}3031func runSCC(args ...string) (string, error) {32 args = slices.Insert(args, 0, sccTestFlag)33 cmd := exec.Command(sccBinPath, args...)34 res, err := cmd.CombinedOutput()35 return string(res), err36}3738func TestNoGitIgnore(t *testing.T) {39 tmpDir := t.TempDir()40 ignoreFileName := filepath.Join(tmpDir, ".gitignore")41 err := os.WriteFile(ignoreFileName, []byte("ignored.xml\n"), 0644)42 if err != nil {43 t.Fatal(err)44 }45 xmlFileName := filepath.Join(tmpDir, "ignored.xml")46 err = os.WriteFile(xmlFileName, []byte(`<?xml version="1.0" encoding="UTF-8"?>`), 0644)47 if err != nil {48 t.Fatal(err)49 }5051 output, err := runSCC(tmpDir)52 if err != nil {53 t.Fatal(err)54 }55 if strings.Contains(output, "XML") {56 t.Fatalf("test --no-gitignore failed, output:\n%s", output)57 }5859 output, err = runSCC("--no-gitignore", tmpDir)60 if err != nil {61 t.Fatal(err)62 }63 if !strings.Contains(output, "XML") {64 t.Fatalf("test --no-gitignore failed, output:\n%s", output)65 }66}6768func TestIssue82(t *testing.T) {69 t.Parallel()70 // Regression issue https://github.com/boyter/scc/issues/8271 output1, err := runSCC(".")72 if err != nil {73 t.Fatal(err)74 }7576 pwd, err := os.Getwd()77 if err != nil {78 t.Fatal(err)79 }80 output2, err := runSCC(pwd)81 if err != nil {82 t.Fatal(err)83 }8485 if output1 != output2 {86 t.Fatalf("`./scc .` not equal to `./scc ${PWD}`")87 }88}8990func TestIncludeExt(t *testing.T) {91 t.Parallel()92 // Regression issue https://github.com/boyter/scc/issues/10893 output, err := runSCC("--include-ext", "go", "examples/language")94 if err != nil {95 t.Fatal(err)96 }97 if !strings.Contains(output, "Go") || strings.Contains(output, "Java") {98 t.Fatalf("include-ext check failed, output:\n%s", output)99 }100}101102func TestIssue115(t *testing.T) {103 t.Parallel()104 // Regression issue https://github.com/boyter/scc/issues/115105 output, err := runSCC("examples/issue115/.test/file")106 if err != nil {107 t.Fatal(err)108 }109 if strings.Contains(output, "Perl") {110 t.Fatalf("Should not print Perl, output:\n%s", output)111 }112}113114func TestIssue120(t *testing.T) {115 t.Parallel()116 // Regression issue https://github.com/boyter/scc/issues/120117 output, err := runSCC("-i", "java", "./examples/issue120")118 if err != nil {119 t.Fatal(err)120 }121 if strings.Contains(output, "Perl") {122 t.Fatal("extension param should ignore Shebang")123 }124}125126func TestIssue152(t *testing.T) {127 t.Parallel()128 // Regression issue https://github.com/boyter/scc/issues/152129 output, err := runSCC("-i", "css", "./examples/issue152/")130 if err != nil {131 t.Fatal(err)132 }133 if !strings.Contains(output, "CSS") {134 t.Fatalf("`-i css` extension check failed, output:\n%s", output)135 }136}137138func TestIssue250(t *testing.T) {139 // Regression issue https://github.com/boyter/scc/issues/250140 output1, err := runSCC("--exclude-dir", "examples/")141 if err != nil {142 t.Fatal(err)143 }144 output2, err := runSCC("--exclude-dir", "examples")145 if err != nil {146 t.Fatal(err)147 }148149 if output1 != output2 {150 t.Fatalf("examples exclude-dir check failed, output1:\n%s, output2:\n%s", output1, output2)151 }152}153154func TestIssue259(t *testing.T) {155 // Regression issue https://github.com/boyter/scc/issues/259156 output, err := runSCC("-f", "csv", "--exclude-ext", "go")157 if err != nil {158 t.Fatal(err)159 }160161 if strings.Contains(output, "Go,") {162 t.Fatalf("exclude-ext check failed, output:\n%s", output)163 }164}165166func TestIssue260(t *testing.T) {167 t.Parallel()168 // Regression issue https://github.com/boyter/scc/issues/260169 _, err := runSCC("-d", "examples/issue260/")170 if err != nil {171 t.Fatalf("duplicate empty crash: %v", err)172 }173}174175func TestIssue345(t *testing.T) {176 t.Parallel()177 // Regression issue https://github.com/boyter/scc/issues/345178 const expectedOutput = "C++,4,3,1,0,0,76,1,0"179 output, err := runSCC("-f", "csv", "--no-scc-ignore", "examples/issue345/")180 if err != nil {181 t.Fatal(err)182 }183 lines := strings.Split(output, "\n")184 if len(lines) < 2 {185 t.Fatalf("wrong output: %s", output)186 }187 if lines[1] != expectedOutput {188 t.Fatalf("got: %s, want: %s", lines[1], expectedOutput)189 }190}191192func TestIssue379(t *testing.T) {193 t.Parallel()194 // Regression issue https://github.com/boyter/scc/issues/379195 const expectedOutput = "Python,7,4,2,1,1,83,1,0"196 output, err := runSCC("-f", "csv", "--no-scc-ignore", "examples/issue379/")197 if err != nil {198 t.Fatal(err)199 }200 lines := strings.Split(output, "\n")201 if len(lines) < 2 {202 t.Fatalf("wrong output: %s", output)203 }204 if lines[1] != expectedOutput {205 t.Fatalf("got: %s, want: %s", lines[1], expectedOutput)206 }207}208209func TestIssue457(t *testing.T) {210 t.Parallel()211 // Regression issue https://github.com/boyter/scc/issues/457212 output, err := runSCC("-M", ".*")213 if err != nil {214 t.Fatal(err)215 }216 if !strings.Contains(output, "0.000 megabytes") {217 t.Fatalf("Issue 457 test failed, output:\n%s", output)218 }219}220221func TestIssue564(t *testing.T) {222 t.Parallel()223 // Regression issue https://github.com/boyter/scc/issues/564224 const expectedPythonOutput = "Python,3,3,0,0,0,84,3,0"225 const expectedGoOutput = "Go,6,4,0,2,0,58,2,0"226 output, err := runSCC("-f", "csv", "--no-scc-ignore", "examples/issue564/")227 if err != nil {228 t.Fatal(err)229 }230 lines := strings.Split(output, "\n")231 if len(lines) < 3 {232 t.Fatalf("wrong output: %s", output)233 }234 if lines[1] != expectedPythonOutput {235 t.Fatalf("got: %s, want: %s", lines[1], expectedPythonOutput)236 }237 if lines[2] != expectedGoOutput {238 t.Fatalf("got: %s, want: %s", lines[2], expectedGoOutput)239 }240}241242func TestIssue610(t *testing.T) {243 t.Parallel()244 // Regression issue https://github.com/boyter/scc/issues/610245 const expectedOutput = "TypeScript,11,7,2,2,1,214,1,0"246 output, err := runSCC("-f", "csv", "--no-scc-ignore", "examples/issue610/")247 if err != nil {248 t.Fatal(err)249 }250 lines := strings.Split(output, "\n")251 if len(lines) < 2 {252 t.Fatalf("wrong output: %s", output)253 }254 if lines[1] != expectedOutput {255 t.Fatalf("got: %s, want: %s", lines[1], expectedOutput)256 }257}258259func TestIssue339(t *testing.T) {260 t.Parallel()261 // Regression issue https://github.com/boyter/scc/issues/339262 output, err := runSCC("-f", "csv", "--no-scc-ignore", "examples/issue339/")263 if err != nil {264 t.Fatal(err)265 }266 if !strings.Contains(output, "MATLAB") {267 t.Errorf("can not find MATLAB, output: %s", output)268 }269 if !strings.Contains(output, "Objective C") {270 t.Errorf("can not find Objective C, output:\n%s", output)271 }272}273274func TestInvalidOption(t *testing.T) {275 t.Parallel()276 output, err := runSCC("--not-a-real-option")277 if err == nil {278 t.Fatal("scc should exit with error code")279 }280 if !strings.Contains(output, "Error: unknown flag: --not-a-real-option") {281 t.Fatalf("scc should report invalid options, output:\n%s", output)282 }283}284285func TestFileFlagSyntax(t *testing.T) {286 tmpDir := t.TempDir()287 flagsFileName := filepath.Join(tmpDir, "flags.txt")288 // include \n, \r\n and no line terminators289 testCases := []string{290 "go.mod\ngo.sum\nLICENSE\n",291 "go.mod\r\ngo.sum\r\nLICENSE\r\n",292 "go.mod\ngo.sum\nLICENSE",293 "go.mod\r\ngo.sum\r\nLICENSE",294 "go.mod\ngo.sum\r\nLICENSE",295 }296297 for _, tc := range testCases {298 err := os.WriteFile(flagsFileName, []byte(tc), 0644)299 if err != nil {300 t.Fatal(err)301 }302 _, err = runSCC("@" + flagsFileName)303 if err != nil {304 t.Errorf("flag syntax faild: %q, %v", tc, err)305 }306 }307}308309func TestLineLength(t *testing.T) {310 t.Parallel()311 output, err := runSCC("-m")312 if err != nil {313 t.Fatal(err)314 }315 if strings.Count(output, "MaxLine / MeanLine") < 2 {316 t.Fatalf("line length test failed, output:\n%s", output)317 }318}319320func TestFormatHTML(t *testing.T) {321 t.Parallel()322 output, err := runSCC("--format", "html")323 if err != nil {324 t.Fatal(err)325 }326 if !strings.Contains(output, "<title>scc html output</title>") {327 t.Fatalf("html format test failed, output:\n%s", output)328 }329}330331func TestFormatHTMLTable(t *testing.T) {332 t.Parallel()333 output, err := runSCC("--format", "html-table")334 if err != nil {335 t.Fatal(err)336 }337 if !strings.Contains(output, `<table id="scc-table">`) {338 t.Fatalf("html-table format test failed, output:\n%s", output)339 }340}341342func TestFormatSQL(t *testing.T) {343 t.Parallel()344 output, err := runSCC("--format", "sql")345 if err != nil {346 t.Fatal(err)347 }348 if !strings.Contains(output, "create table metadata ( -- github.com/boyter/scc") {349 t.Fatalf("sql format test failed, output:\n%s", output)350 }351}352353func TestFormatSQLInsert(t *testing.T) {354 t.Parallel()355 output, err := runSCC("--format", "sql-insert")356 if err != nil {357 t.Fatal(err)358 }359 if !strings.Contains(output, "begin transaction;\ninsert into t values(") {360 t.Fatalf("sql-insert format test failed, output:\n%s", output)361 }362}363364func TestMultipleFormatStdout(t *testing.T) {365 output, err := runSCC("--format-multi", "tabular:stdout,html:stdout,csv:stdout,sql:stdout")366 if err != nil {367 t.Fatal(err)368 }369370 tabularPattern := regexp.MustCompile(`Processed .+? bytes, .+? megabytes \(SI\)`)371 if !tabularPattern.MatchString(output) {372 t.Errorf("multi-format tabular failed, output:\n%s", output)373 }374375 if !strings.Contains(output, `<html lang="en"><head><meta charset="utf-8" /><title>scc html output</title>`) {376 t.Errorf("multi-format html failed, output:\n%s", output)377 }378379 if !strings.Contains(output, "Language,Lines,Code,Comments,Blanks,Complexity,Bytes,Files,ULOC") {380 t.Errorf("multi-format csv failed, output:\n%s", output)381 }382383 sqlPattern := regexp.MustCompile(`insert into t values\(.+?\);`)384 if !sqlPattern.MatchString(output) {385 t.Errorf("multi-format sql failed, output:\n%s", output)386 }387}388389func TestMultipleFormatWriteFile(t *testing.T) {390 tmpDir := t.TempDir()391 outputTabular := filepath.Join(tmpDir, "output.tab")392 outputWide := filepath.Join(tmpDir, "output.wide")393 outputJSON1 := filepath.Join(tmpDir, "output.json")394 outputJSON2 := filepath.Join(tmpDir, "output2.json")395 outputCSV := filepath.Join(tmpDir, "output.csv")396 outputYAML := filepath.Join(tmpDir, "output.yaml")397 outputHTML := filepath.Join(tmpDir, "output.html")398 outputHTMLTable := filepath.Join(tmpDir, "output_table.html")399 outputSQL := filepath.Join(tmpDir, "output.sql")400401 multiFormatArgs := fmt.Sprintf(402 "tabular:%s,wide:%s,json:%s,json2:%s,csv:%s,cloc-yaml:%s,html:%s,html-table:%s,sql:%s",403 outputTabular,404 outputWide,405 outputJSON1,406 outputJSON2,407 outputCSV,408 outputYAML,409 outputHTML,410 outputHTMLTable,411 outputSQL,412 )413414 _, err := runSCC("--format-multi", multiFormatArgs)415 if err != nil {416 t.Fatal(err)417 }418419 if info, err := os.Stat(outputTabular); err != nil || info.Size() <= 0 {420 t.Fatal("tabular write file test failed")421 }422 if info, err := os.Stat(outputWide); err != nil || info.Size() <= 0 {423 t.Fatal("wide write file test failed")424 }425 if info, err := os.Stat(outputJSON1); err != nil || info.Size() <= 0 {426 t.Fatal("json write file test failed")427 }428 if info, err := os.Stat(outputJSON2); err != nil || info.Size() <= 0 {429 t.Fatal("json2 write file test failed")430 }431 if info, err := os.Stat(outputCSV); err != nil || info.Size() <= 0 {432 t.Fatal("csv write file test failed")433 }434 if info, err := os.Stat(outputYAML); err != nil || info.Size() <= 0 {435 t.Fatal("cloc-yaml write file test failed")436 }437 if info, err := os.Stat(outputHTML); err != nil || info.Size() <= 0 {438 t.Fatal("html write file test failed")439 }440 if info, err := os.Stat(outputHTMLTable); err != nil || info.Size() <= 0 {441 t.Fatal("html-table write file test failed")442 }443 if info, err := os.Stat(outputSQL); err != nil || info.Size() <= 0 {444 t.Fatal("sql write file test failed")445 }446}447448func TestRecursivelyIgnore(t *testing.T) {449 tmpDir := t.TempDir()450 err := os.WriteFile(filepath.Join(tmpDir, ".gitignore"), []byte("ignore-git.txt\n"), 0644)451 if err != nil {452 t.Fatal(err)453 }454 err = os.WriteFile(filepath.Join(tmpDir, ".ignore"), []byte("vendor/\nignore.txt\n"), 0644)455 if err != nil {456 t.Fatal(err)457 }458 err = os.Mkdir(filepath.Join(tmpDir, "ignore"), 0755)459 if err != nil {460 t.Fatal(err)461 }462 err = os.WriteFile(filepath.Join(tmpDir, "ignore", "README.md"), []byte("Files in here are to ensure that .ignore and .gitignore work recursively\n"), 0644)463 if err != nil {464 t.Fatal(err)465 }466 err = os.WriteFile(filepath.Join(tmpDir, "ignore", "ignore.txt"), []byte("testing\n"), 0644)467 if err != nil {468 t.Fatal(err)469 }470 err = os.WriteFile(filepath.Join(tmpDir, "ignore", "ignore-git.txt"), []byte("git\ntesting\n"), 0644)471 if err != nil {472 t.Fatal(err)473 }474475 output, err := runSCC("--by-file", "--no-scc-ignore", tmpDir)476 if err != nil {477 t.Fatal(err)478 }479 if strings.Contains(output, "ignore.txt") || strings.Contains(output, "ignore-git.txt") {480 t.Errorf("ignore recursive filter failed, output:\n%s", output)481 }482483 output, err = runSCC("--by-file", "--no-scc-ignore", "--no-ignore", tmpDir)484 if err != nil {485 t.Fatal(err)486 }487 if !strings.Contains(output, "ignore.txt") || strings.Contains(output, "ignore-git.txt") {488 t.Errorf("ignore recursive filter failed, output:\n%s", output)489 }490491 output, err = runSCC("--by-file", "--no-scc-ignore", "--no-gitignore", tmpDir)492 if err != nil {493 t.Fatal(err)494 }495 if strings.Contains(output, "ignore.txt") || !strings.Contains(output, "ignore-git.txt") {496 t.Errorf("ignore recursive filter failed, output:\n%s", output)497 }498499 output, err = runSCC("--by-file", "--no-scc-ignore", "--no-ignore", "--no-gitignore", tmpDir)500 if err != nil {501 t.Fatal(err)502 }503 if !strings.Contains(output, "ignore.txt") || !strings.Contains(output, "ignore-git.txt") {504 t.Errorf("ignore recursive filter failed, output:\n%s", output)505 }506}507508func TestMultipleGitIgnore(t *testing.T) {509 tmpDir := t.TempDir()510 err := os.WriteFile(filepath.Join(tmpDir, ".gitignore"), []byte("ignore.txt\n"), 0644)511 if err != nil {512 t.Fatal(err)513 }514 err = os.Mkdir(filepath.Join(tmpDir, "ignore"), 0755)515 if err != nil {516 t.Fatal(err)517 }518 err = os.WriteFile(filepath.Join(tmpDir, "ignore", ".gitignore"), []byte("ignore.java\n"), 0644)519 if err != nil {520 t.Fatal(err)521 }522 err = os.WriteFile(filepath.Join(tmpDir, "ignore", "ignore.java"), []byte("//test\n"), 0644)523 if err != nil {524 t.Fatal(err)525 }526527 output, err := runSCC(tmpDir)528 if err != nil {529 t.Fatal(err)530 }531 if strings.Contains(output, "Java") {532 t.Fatalf("multiple gitignore failed, output:\n%s", output)533 }534}535536func TestFlagSuggestion(t *testing.T) {537 t.Parallel()538 testCases := []struct {539 args []string540 expectedOutput string541 }{542 {543 args: []string{"--farmat"},544 expectedOutput: "The most similar flag of --farmat is:\n\t--format\n",545 },546 {547 args: []string{"--no-gignore"},548 expectedOutput: "The most similar flags of --no-gignore are:\n\t--no-ignore\n\t--no-gitignore\n",549 },550 }551552 for _, tc := range testCases {553 output, err := runSCC(tc.args...)554 if err == nil {555 t.Fatal("scc should exit with error code")556 }557 if !strings.Contains(output, tc.expectedOutput) {558 t.Errorf("wrong suggestion for %v, want: %s, got: %s", tc.args, tc.expectedOutput, output)559 }560 }561}562563func TestDeterministicOutput(t *testing.T) {564 output, err := runSCC(".")565 if err != nil {566 t.Fatal(err)567 }568 for range 10 {569 output2, err := runSCC(".")570 if err != nil {571 t.Fatal(err)572 }573 if output != output2 {574 t.Fatalf("want:\n%s, got:\n%s", output, output2)575 }576 }577}578579func TestDuplicates(t *testing.T) {580 for range 10 {581 output, err := runSCC("-f", "json", "-d", "./examples/duplicates/")582 if err != nil {583 t.Fatal(err)584 }585 if !strings.Contains(output, `"Count":1`) {586 t.Fatalf("duplicates check failed, output:\n%s", output)587 }588 }589}590591func TestCountAs(t *testing.T) {592 testCases := []struct {593 countAs string594 expected []string595 }{596 {597 countAs: "jsp:html",598 expected: []string{"HTML"},599 },600 {601 countAs: "JsP:html",602 expected: []string{"HTML"},603 },604 {605 countAs: "jsp:j2",606 expected: []string{"Jinja"},607 },608 {609 countAs: "jsp:html,new:java",610 expected: []string{"HTML", "Java"},611 },612 {613 countAs: "jsp:html,new:C Header",614 expected: []string{"HTML", "C Header"},615 },616 }617618 for _, tc := range testCases {619 output, err := runSCC("-f", "csv", "--count-as", tc.countAs, "./examples/countas/")620 if err != nil {621 t.Fatal(err)622 }623 for _, expectedLang := range tc.expected {624 if !strings.Contains(output, expectedLang+",") {625 t.Errorf("count as failed, count as: %s, output:\n%s", tc.countAs, output)626 }627 }628 }629}630631func TestRemapUnknown(t *testing.T) {632 t.Parallel()633 output, err := runSCC("-f", "csv", "--remap-unknown", "-*- C++ -*-:C Header", "./examples/remap/unknown")634 if err != nil {635 t.Fatal(err)636 }637 if !strings.Contains(output, "C Header,") {638 t.Fatalf("remap unknown failed, output:\n%s", output)639 }640}641642func TestRemapAll(t *testing.T) {643 t.Parallel()644 output, err := runSCC("-f", "csv", "--remap-all", "-*- C++ -*-:C Header", "./examples/remap/java.java")645 if err != nil {646 t.Fatal(err)647 }648 if !strings.Contains(output, "C Header,") {649 t.Fatalf("remap all failed, output:\n%s", output)650 }651}652653func TestCocomoProjectType(t *testing.T) {654 projectTypes := []string{"organic", "semi-detached", "embedded", "custom,1,1,1,1"}655 for _, typ := range projectTypes {656 output, err := runSCC("--cocomo-project-type", typ)657 if err != nil {658 t.Fatal(err)659 }660 if !strings.Contains(output, fmt.Sprintf("Estimated Cost to Develop (%s)", typ)) ||661 !strings.Contains(output, fmt.Sprintf("Estimated Schedule Effort (%s)", typ)) ||662 !strings.Contains(output, fmt.Sprintf("Estimated People Required (%s)", typ)) {663 t.Errorf("check cocomo project type failed: %s", typ)664 }665 }666}667668func TestCocomoProjectTypeFallback(t *testing.T) {669 unknownTypes := []string{"doesnotexist", "custom,1,1,1"}670 for _, typ := range unknownTypes {671 output, err := runSCC("--cocomo-project-type", typ)672 if err != nil {673 t.Fatal(err)674 }675 if !strings.Contains(output, "Estimated Cost to Develop (organic)") ||676 !strings.Contains(output, "Estimated Schedule Effort (organic)") ||677 !strings.Contains(output, "Estimated People Required (organic)") {678 t.Errorf("check cocomo project type fallback failed: %s", typ)679 }680 }681}682683func TestOutputBytes(t *testing.T) {684 jsonOutput, err := runSCC("-f", "json")685 if err != nil {686 t.Fatal(err)687 }688 if !strings.Contains(jsonOutput, `"Bytes":`) {689 t.Errorf("json output does not contain `Bytes` field, output:\n%s", jsonOutput)690 }691692 output, err := runSCC()693 if err != nil {694 t.Fatal(err)695 }696 if !strings.Contains(output, "megabytes") {697 t.Errorf("output does not contain `megabytes`, output:\n%s", output)698 }699}700701func TestFileGCCount(t *testing.T) {702 const target = "./examples/duplicates"703 files, err := os.ReadDir(target)704 if err != nil {705 t.Fatal(err)706 }707708 output, err := runSCC("--file-gc-count", strconv.Itoa(len(files)-1), "-v", target)709 if err != nil {710 t.Fatal(err)711 }712 if !strings.Contains(output, "read file limit exceeded GC re-enabled") {713 t.Errorf("test file GC count failed, file count: %d, limit: %d", len(files), len(files)-1)714 }715716 output, err = runSCC("--file-gc-count", strconv.Itoa(len(files)+1), "-v", target)717 if err != nil {718 t.Fatal(err)719 }720 if strings.Contains(output, "read file limit exceeded GC re-enabled") {721 t.Errorf("test file GC count failed, file count: %d, limit: %d", len(files), len(files)+1)722 }723}724725func TestIncludeSymlinks(t *testing.T) {726 if runtime.GOOS == "windows" {727 t.Skip("skipping symlink test on Windows due to privilege requirements")728 }729730 tmpDir, err := filepath.EvalSymlinks(t.TempDir())731 if err != nil {732 t.Fatal(err)733 }734735 dirA := filepath.Join(tmpDir, "a")736 dirB := filepath.Join(tmpDir, "b")737 if err := os.Mkdir(dirA, 0755); err != nil {738 t.Fatal(err)739 }740 if err := os.Mkdir(dirB, 0755); err != nil {741 t.Fatal(err)742 }743744 const fileName = "source.go"745 if err := os.WriteFile(filepath.Join(dirA, fileName), []byte("package main\n"), 0644); err != nil {746 t.Fatal(err)747 }748 if err := os.WriteFile(filepath.Join(dirB, fileName), []byte("package main\n"), 0644); err != nil {749 t.Fatal(err)750 }751 // link to another dir, should be counted under --include-symlinks752 if err := os.Symlink(filepath.Join(dirB, fileName), filepath.Join(dirA, "link1.go")); err != nil {753 t.Fatal(err)754 }755 // link to the same dir, this should be ignored in all times756 if err := os.Symlink(filepath.Join(dirA, fileName), filepath.Join(dirA, "link2.go")); err != nil {757 t.Fatal(err)758 }759760 output, err := runSCC("-f", "json", "--no-scc-ignore", dirA)761 if err != nil {762 t.Fatal(err)763 }764 if !strings.Contains(output, `"Count":1`) {765 t.Errorf("count without symlink failed, output:\n%s", output)766 }767768 output, err = runSCC("-f", "json", "--no-scc-ignore", "--include-symlinks", dirA)769 if err != nil {770 t.Fatal(err)771 }772 if !strings.Contains(output, `"Count":2`) {773 t.Errorf("count includes symlink failed, output:\n%s", output)774 }775}776777func TestLanguageNameTruncate(t *testing.T) {778 output, err := runSCC("examples/language")779 if err != nil {780 t.Fatal(err)781 }782 if strings.Count(output, "Bitbucket Pipe…") != 1 {783 t.Errorf("`Bitbucket Pipeline` truncate test failed")784 }785 if strings.Count(output, "CloudFormation…") != 2 {786 t.Errorf("`CloudFormation (JSON)` and `CloudFormation (YAML)` truncate test failed")787 }788}789790func TestSpecificLanguages(t *testing.T) {791 languages := [...]string{792 "ABNF",793 "Alchemist",794 "Algol 68",795 "Alloy",796 "Amber",797 "Apex",798 "ArkTs",799 "Arturo",800 "Astro",801 "AWK",802 "BASH",803 "Bean",804 "Bicep",805 "Bitbucket Pipeline",806 "Blueprint",807 "Boo",808 "Bosque",809 "Bru",810 "C",811 "C3",812 "C Header",813 "C Shell",814 "C#",815 "C++",816 "C++ Header",817 "Cairo",818 "Cangjie",819 "Chapel",820 "Circom",821 "Clipper",822 "Clojure",823 "CMake",824 "Cuda",825 "Cypher",826 "D2",827 "DAML",828 "DM",829 "Docker ignore",830 "Dockerfile",831 "DOT",832 "Elixir Template",833 "Elm",834 "EmiT",835 "F#",836 "Factor",837 "Flow9",838 "FSL",839 "Futhark",840 "FXML",841 "Gemfile",842 "Gleam",843 "Go",844 "Go+",845 "Godot Scene",846 "GraphQL",847 "Gremlin",848 "Gwion",849 "HAML",850 "Hare",851 "Haskell",852 "HCL",853 "IEC61131-3",854 "ignore",855 "INI",856 "Java",857 "JavaScript",858 "JCL",859 "JSON5",860 "JSONC",861 "jq",862 "Korn Shell",863 "Koto",864 "LALRPOP",865 "License",866 "LiveScript",867 "LLVM IR",868 "Lua",869 "Luau",870 "Luna",871 "MLIR",872 "Makefile",873 "Metal",874 "Mojo",875 "Monkey C",876 "Moonbit",877 "Move",878 "Nature",879 "Nushell",880 "OpenQASM",881 "OpenTofu",882 "Perl",883 "Pkl",884 "Plain Text",885 "POML",886 "PostScript",887 "Proto",888 "Python",889 "Q#",890 "R",891 "Racket",892 "Rakefile",893 "RAML",894 "Rebol",895 "Redscript",896 "Rich Text Format",897 "Scallop",898 "Seed7",899 "Shell",900 "Sieve",901 "Slang",902 "Slint",903 "Smalltalk",904 "Snakemake",905 "Stan",906 "Systemd",907 "Tact",908 "Teal",909 "Tera",910 "Templ",911 "Terraform",912 "TOML",913 "TOON",914 "TTCN-3",915 "TypeScript",916 "TypeSpec",917 "Typst",918 "Up",919 "Vala",920 "Vim Script",921 "Web Services Description Language",922 "WebGPU Enhanced Shading Language",923 "wenyan",924 "Wren",925 "XHTML",926 "XMake",927 "XML Schema",928 "YAML",929 "Yarn",930 "Zig",931 "ZoKrates",932 "Zsh",933 }934935 output, err := runSCC("-f", "csv", "examples/language")936 if err != nil {937 t.Fatal(err)938 }939940 for _, language := range languages {941 if !strings.Contains(output, language+",") {942 t.Errorf("language not found in output: %v", language)943 }944 }945}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.