package main import ( "io/ioutil" "os" "os/exec" "path/filepath" "strings" "testing" ) func testCompiler(t *testing.T, inputFile string, referenceFile string, expectErrors bool) { textFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".text", 1) errorsFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".errors", 1) // remove any preexisting output files os.Remove(textFile) os.Remove(errorsFile) // run the compiler var err error var cmd = exec.Command( "gnostic", inputFile, "--text-out=.", "--errors-out=.", "--resolve-refs") //t.Log(cmd.Args) err = cmd.Run() if err != nil && !expectErrors { t.Logf("Compile failed: %+v", err) t.FailNow() } // verify the output against a reference var outputFile string if expectErrors { outputFile = errorsFile } else { outputFile = textFile } err = exec.Command("diff", outputFile, referenceFile).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(textFile) os.Remove(errorsFile) } } func testNormal(t *testing.T, inputFile string, referenceFile string) { testCompiler(t, inputFile, referenceFile, false) } func testErrors(t *testing.T, inputFile string, referenceFile string) { testCompiler(t, inputFile, referenceFile, true) } func TestPetstoreJSON(t *testing.T) { testNormal(t, "examples/v2.0/json/petstore.json", "test/v2.0/petstore.text") } func TestPetstoreYAML(t *testing.T) { testNormal(t, "examples/v2.0/yaml/petstore.yaml", "test/v2.0/petstore.text") } func TestSeparateYAML(t *testing.T) { testNormal(t, "examples/v2.0/yaml/petstore-separate/spec/swagger.yaml", "test/v2.0/yaml/petstore-separate/spec/swagger.text") } func TestSeparateJSON(t *testing.T) { testNormal(t, "examples/v2.0/json/petstore-separate/spec/swagger.json", "test/v2.0/yaml/petstore-separate/spec/swagger.text") // yaml and json results should be identical } func TestRemotePetstoreJSON(t *testing.T) { testNormal(t, "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore.json", "test/v2.0/petstore.text") } func TestRemotePetstoreYAML(t *testing.T) { testNormal(t, "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore.yaml", "test/v2.0/petstore.text") } func TestRemoteSeparateYAML(t *testing.T) { testNormal(t, "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore-separate/spec/swagger.yaml", "test/v2.0/yaml/petstore-separate/spec/swagger.text") } func TestRemoteSeparateJSON(t *testing.T) { testNormal(t, "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore-separate/spec/swagger.json", "test/v2.0/yaml/petstore-separate/spec/swagger.text") } func TestErrorBadProperties(t *testing.T) { testErrors(t, "examples/errors/petstore-badproperties.yaml", "test/errors/petstore-badproperties.errors") } func TestErrorUnresolvedRefs(t *testing.T) { testErrors(t, "examples/errors/petstore-unresolvedrefs.yaml", "test/errors/petstore-unresolvedrefs.errors") } func TestErrorMissingVersion(t *testing.T) { testErrors(t, "examples/errors/petstore-missingversion.yaml", "test/errors/petstore-missingversion.errors") } func testPlugin(t *testing.T, plugin string, inputFile string, outputFile string, referenceFile string) { // remove any preexisting output files os.Remove(outputFile) // run the compiler var err error output, err := exec.Command( "gnostic", "--"+plugin+"-out=-", inputFile).Output() if err != nil { t.Logf("Compile failed: %+v", err) t.FailNow() } _ = ioutil.WriteFile(outputFile, output, 0644) err = exec.Command("diff", outputFile, referenceFile).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(outputFile) } } func TestSamplePluginWithPetstore(t *testing.T) { testPlugin(t, "summary", "examples/v2.0/yaml/petstore.yaml", "sample-petstore.out", "test/v2.0/yaml/sample-petstore.out") } func TestErrorInvalidPluginInvocations(t *testing.T) { var err error output, err := exec.Command( "gnostic", "examples/v2.0/yaml/petstore.yaml", "--errors-out=-", "--plugin-out=foo=bar,:abc", "--plugin-out=,foo=bar:abc", "--plugin-out=foo=:abc", "--plugin-out==bar:abc", "--plugin-out=,,:abc", "--plugin-out=foo=bar=baz:abc", ).Output() if err == nil { t.Logf("Invalid invocations were accepted") t.FailNow() } outputFile := "invalid-plugin-invocation.errors" _ = ioutil.WriteFile(outputFile, output, 0644) err = exec.Command("diff", outputFile, "test/errors/invalid-plugin-invocation.errors").Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(outputFile) } } func TestValidPluginInvocations(t *testing.T) { var err error output, err := exec.Command( "gnostic", "examples/v2.0/yaml/petstore.yaml", "--errors-out=-", // verify an invocation with no parameters "--summary-out=!", // "!" indicates that no output should be generated // verify single pair of parameters "--summary-out=a=b:!", // verify multiple parameters "--summary-out=a=b,c=123,xyz=alphabetagammadelta:!", // verify that special characters / . - _ can be included in parameter keys and values "--summary-out=a/b/c=x/y/z:!", "--summary-out=a.b.c=x.y.z:!", "--summary-out=a-b-c=x-y-z:!", "--summary-out=a_b_c=x_y_z:!", ).Output() if len(output) != 0 { t.Logf("Valid invocations generated invalid errors\n%s", string(output)) t.FailNow() } if err != nil { t.Logf("Valid invocations were not accepted") t.FailNow() } } func TestExtensionHandlerWithLibraryExample(t *testing.T) { outputFile := "library-example-with-ext.text.out" inputFile := "test/library-example-with-ext.json" referenceFile := "test/library-example-with-ext.text.out" os.Remove(outputFile) // run the compiler var err error command := exec.Command( "gnostic", "--x-sampleone", "--x-sampletwo", "--text-out="+outputFile, "--resolve-refs", inputFile) _, err = command.Output() if err != nil { t.Logf("Compile failed for command %v: %+v", command, err) t.FailNow() } //_ = ioutil.WriteFile(outputFile, output, 0644) err = exec.Command("diff", outputFile, referenceFile).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(outputFile) } } func TestJSONOutput(t *testing.T) { inputFile := "test/library-example-with-ext.json" textFile := "sample.text" jsonFile := "sample.json" textFile2 := "sample2.text" jsonFile2 := "sample2.json" os.Remove(textFile) os.Remove(jsonFile) os.Remove(textFile2) os.Remove(jsonFile2) var err error // Run the compiler once. command := exec.Command( "gnostic", "--text-out="+textFile, "--json-out="+jsonFile, inputFile) _, err = command.Output() if err != nil { t.Logf("Compile failed for command %v: %+v", command, err) t.FailNow() } // Run the compiler again, this time on the generated output. command = exec.Command( "gnostic", "--text-out="+textFile2, "--json-out="+jsonFile2, jsonFile) _, err = command.Output() if err != nil { t.Logf("Compile failed for command %v: %+v", command, err) t.FailNow() } // Verify that both models have the same internal representation. err = exec.Command("diff", textFile, textFile2).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(textFile) os.Remove(jsonFile) os.Remove(textFile2) os.Remove(jsonFile2) } } func TestYAMLOutput(t *testing.T) { inputFile := "test/library-example-with-ext.json" textFile := "sample.text" yamlFile := "sample.yaml" textFile2 := "sample2.text" yamlFile2 := "sample2.yaml" os.Remove(textFile) os.Remove(yamlFile) os.Remove(textFile2) os.Remove(yamlFile2) var err error // Run the compiler once. command := exec.Command( "gnostic", "--text-out="+textFile, "--yaml-out="+yamlFile, inputFile) _, err = command.Output() if err != nil { t.Logf("Compile failed for command %v: %+v", command, err) t.FailNow() } // Run the compiler again, this time on the generated output. command = exec.Command( "gnostic", "--text-out="+textFile2, "--yaml-out="+yamlFile2, yamlFile) _, err = command.Output() if err != nil { t.Logf("Compile failed for command %v: %+v", command, err) t.FailNow() } // Verify that both models have the same internal representation. err = exec.Command("diff", textFile, textFile2).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(textFile) os.Remove(yamlFile) os.Remove(textFile2) os.Remove(yamlFile2) } } func testBuilder(version string, t *testing.T) { var err error pbFile := "petstore-" + version + ".pb" yamlFile := "petstore.yaml" jsonFile := "petstore.json" textFile := "petstore.text" textReference := "test/" + version + ".0/petstore.text" os.Remove(pbFile) os.Remove(textFile) os.Remove(yamlFile) os.Remove(jsonFile) // Generate petstore.pb. command := exec.Command( "petstore-builder", "--"+version) _, err = command.Output() if err != nil { t.Logf("Command %v failed: %+v", command, err) t.FailNow() } // Convert petstore.pb to yaml and json. command = exec.Command( "gnostic", pbFile, "--json-out="+jsonFile, "--yaml-out="+yamlFile) _, err = command.Output() if err != nil { t.Logf("Command %v failed: %+v", command, err) t.FailNow() } // Read petstore.yaml, resolve references, and export text. command = exec.Command( "gnostic", yamlFile, "--resolve-refs", "--text-out="+textFile) _, err = command.Output() if err != nil { t.Logf("Command %v failed: %+v", command, err) t.FailNow() } // Verify that the generated text matches our reference. err = exec.Command("diff", textFile, textReference).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } // Read petstore.json, resolve references, and export text. command = exec.Command( "gnostic", jsonFile, "--resolve-refs", "--text-out="+textFile) _, err = command.Output() if err != nil { t.Logf("Command %v failed: %+v", command, err) t.FailNow() } // Verify that the generated text matches our reference. err = exec.Command("diff", textFile, textReference).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } // if the test succeeded, clean up os.Remove(pbFile) os.Remove(textFile) os.Remove(yamlFile) os.Remove(jsonFile) } func TestBuilderV2(t *testing.T) { testBuilder("v2", t) } func TestBuilderV3(t *testing.T) { testBuilder("v3", t) } // OpenAPI 3.0 tests func TestPetstoreYAML_30(t *testing.T) { testNormal(t, "examples/v3.0/yaml/petstore.yaml", "test/v3.0/petstore.text") } func TestPetstoreJSON_30(t *testing.T) { testNormal(t, "examples/v3.0/json/petstore.json", "test/v3.0/petstore.text") }