package builder import ( "strings" "testing" ) // A language the mesh builds resolves to the toolchain that builds it. func TestADeclaredLanguageSelectsItsToolchain(t *testing.T) { chain, err := ToolchainFor("typescript") if err != nil { t.Fatalf("typescript is not buildable: %v", err) } if chain.Base == "" || chain.Artifact == "" { t.Fatalf("a toolchain names no base to compile in: %+v", chain) } if len(chain.Compile) == 0 { t.Fatalf("a toolchain says nothing about how to compile: %+v", chain) } } // Case and stray whitespace are a module author's slip, not a different language. func TestALanguageIsMatchedLoosely(t *testing.T) { for _, said := range []string{"TypeScript", " typescript ", "TYPESCRIPT"} { if _, err := ToolchainFor(said); err != nil { t.Fatalf("%q was refused: %v", said, err) } } } // **A refusal says what would have worked.** A module author who names a language the mesh does // not build is one word away from a language it does, and a bare "unsupported" makes them go // looking for a list that exists in one place in the source. func TestAnUnknownLanguageSaysWhatIsBuildable(t *testing.T) { _, err := ToolchainFor("cobol") if err == nil { t.Fatal("a language nothing can build was accepted") } for _, want := range Languages() { if !strings.Contains(err.Error(), want) { t.Fatalf("the refusal does not mention %q, which would have worked: %v", want, err) } } } // And saying nothing is its own message: the mesh chooses the compiler, so a bundle that names no // language has not asked for anything in particular — which is a mistake rather than a default. func TestABundleMustSayWhatItIsWrittenIn(t *testing.T) { _, err := ToolchainFor("") if err == nil { t.Fatal("a bundle with no language was accepted, so the mesh guessed a compiler") } if !strings.Contains(err.Error(), "must say") { t.Fatalf("the refusal does not say a language is required: %v", err) } } // **One module, several languages, and each bundle packed alone.** // // A module is one piece of software (ADR 0040) and may still carry a daemon in one language, tools // in another and a package in a third. Compiling them into one output directory would have them // overwrite each other and then be packed together, so output is a property of the artifact rather // than of the toolchain. func TestTwoBundlesInOneModuleDoNotShareAnOutputDirectory(t *testing.T) { first, second := Out("daemon"), Out("tools") if first == second { t.Fatalf("two artifacts compile into the same place (%q), so one would overwrite the "+ "other and both would be packed together", first) } for _, out := range []string{first, second} { if strings.HasPrefix(out, "/") || strings.Contains(out, "..") { t.Fatalf("%q leaves the module's own directory", out) } } } // And the mesh can say what it builds, which is what a refusal quotes. func TestTheMeshSaysWhichLanguagesItBuilds(t *testing.T) { spoken := Languages() if len(spoken) < 2 { t.Fatalf("only %v — this test exists to keep the multi-language path real rather than "+ "theoretical", spoken) } for _, language := range spoken { if _, err := ToolchainFor(language); err != nil { t.Fatalf("%q is listed as buildable and has no toolchain: %v", language, err) } } }