// Copyright 2017 Google LLC. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "net/url" "os" "os/exec" "path/filepath" "strings" "testing" "github.com/googleapis/gnostic/lib" ) func isURL(path string) bool { _, err := url.ParseRequestURI(path) if err != nil { return false } u, err := url.Parse(path) if err != nil || u.Scheme == "" || u.Host == "" { return false } return true } func testCompiler(t *testing.T, inputFile string, referenceFile string, expectErrors bool) { outputFormat := filepath.Ext(referenceFile)[1:] outputFile := strings.Replace(inputFile, filepath.Ext(inputFile), "."+outputFormat, 1) errorsFile := strings.Replace(inputFile, filepath.Ext(inputFile), ".errors", 1) if isURL(inputFile) { // put outputs in the current directory outputFile = filepath.Base(outputFile) errorsFile = filepath.Base(errorsFile) } // remove any preexisting output files os.Remove(outputFile) os.Remove(errorsFile) var err error // run the compiler args := []string{ "gnostic", inputFile, "--" + outputFormat + "-out=.", "--errors-out=.", "--resolve-refs"} g := lib.NewGnostic(args) err = g.Main() // verify the output against a reference var testFile string if expectErrors { testFile = errorsFile } else { testFile = outputFile } err = exec.Command("diff", testFile, referenceFile).Run() if err != nil { t.Logf("Diff failed: %+v", err) t.FailNow() } else { // if the test succeeded, clean up os.Remove(outputFile) 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", "testdata/v2.0/petstore.text") } func TestPetstoreYAML(t *testing.T) { testNormal(t, "examples/v2.0/yaml/petstore.yaml", "testdata/v2.0/petstore.text") } func TestSeparateYAML(t *testing.T) { testNormal(t, "examples/v2.0/yaml/petstore-separate/spec/swagger.yaml", "testdata/v2.0/yaml/petstore-separate/spec/swagger.text") } func TestSeparateJSON(t *testing.T) { testNormal(t, "examples/v2.0/json/petstore-separate/spec/swagger.json", "testdata/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", "testdata/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", "testdata/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", "testdata/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", "testdata/v2.0/yaml/petstore-separate/spec/swagger.text") } func TestErrorBadProperties(t *testing.T) { testErrors(t, "examples/errors/petstore-badproperties.yaml", "testdata/errors/petstore-badproperties.errors") } func TestErrorUnresolvedRefs(t *testing.T) { testErrors(t, "examples/errors/petstore-unresolvedrefs.yaml", "testdata/errors/petstore-unresolvedrefs.errors") } func TestErrorMissingVersion(t *testing.T) { testErrors(t, "examples/errors/petstore-missingversion.yaml", "testdata/errors/petstore-missingversion.errors") } func TestJSONOutput(t *testing.T) { inputFile := "testdata/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. args := []string{ "gnostic", "--text-out=" + textFile, "--json-out=" + jsonFile, inputFile} g := lib.NewGnostic(args) err = g.Main() if err != nil { t.Logf("Compile failed for command %v: %+v", strings.Join(args, " "), err) t.FailNow() } // Run the compiler again, this time on the generated output. args = []string{ "gnostic", "--text-out=" + textFile2, "--json-out=" + jsonFile2, jsonFile} g = lib.NewGnostic(args) err = g.Main() if err != nil { t.Logf("Compile failed for command %v: %+v", strings.Join(args, " "), 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 (%s vs %s): %+v", textFile, textFile2, 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 := "testdata/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. args := []string{ "gnostic", "--text-out=" + textFile, "--yaml-out=" + yamlFile, inputFile} g := lib.NewGnostic(args) err = g.Main() if err != nil { t.Logf("Compile failed for command %v: %+v", strings.Join(args, " "), err) t.FailNow() } // Run the compiler again, this time on the generated output. args = []string{ "gnostic", "--text-out=" + textFile2, "--yaml-out=" + yamlFile2, yamlFile} g = lib.NewGnostic(args) err = g.Main() if err != nil { t.Logf("Compile failed for command %v: %+v", strings.Join(args, " "), 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) } } // OpenAPI 3.0 tests func TestPetstoreYAML_30(t *testing.T) { testNormal(t, "examples/v3.0/yaml/petstore.yaml", "testdata/v3.0/petstore.text") } func TestPetstoreJSON_30(t *testing.T) { testNormal(t, "examples/v3.0/json/petstore.json", "testdata/v3.0/petstore.text") } // Test that empty required fields are exported. func TestEmptyRequiredFields_v2(t *testing.T) { testNormal(t, "examples/v2.0/yaml/empty-v2.yaml", "testdata/v2.0/json/empty-v2.json") } func TestEmptyRequiredFields_v3(t *testing.T) { testNormal(t, "examples/v3.0/yaml/empty-v3.yaml", "testdata/v3.0/json/empty-v3.json") } func TestDiscoveryJSON(t *testing.T) { testNormal(t, "examples/discovery/discovery-v1.json", "testdata/discovery/discovery-v1.text") }