github.com/kaptinlin/jsonschema@v0.4.6/tests/utils.go (about)

     1  package tests
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/goccy/go-json"
    14  	"github.com/kaptinlin/jsonschema"
    15  )
    16  
    17  // Helper function to create *float64
    18  func ptrFloat64(v float64) *float64 {
    19  	return &v
    20  }
    21  
    22  // Helper function to create *string
    23  func ptrString(v string) *string {
    24  	return &v
    25  }
    26  
    27  // startTestServer starts an HTTP server for serving remote schemas.
    28  func startTestServer() *http.Server {
    29  	server := &http.Server{
    30  		Addr:              ":1234",
    31  		Handler:           http.FileServer(http.Dir("../testdata/JSON-Schema-Test-Suite/remotes")),
    32  		ReadHeaderTimeout: 1 * time.Second,
    33  	}
    34  
    35  	go func() {
    36  		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
    37  			log.Fatalf("Failed to start server: %v", err)
    38  		}
    39  	}()
    40  
    41  	// Give the server a moment to start
    42  	time.Sleep(100 * time.Millisecond)
    43  	return server
    44  }
    45  
    46  // stopTestServer stops the given HTTP server.
    47  func stopTestServer(server *http.Server) {
    48  	if err := server.Shutdown(context.TODO()); err != nil {
    49  		log.Fatalf("Failed to shutdown server: %v", err)
    50  	}
    51  }
    52  
    53  // TestJSONSchemaTestSuiteWithFilePath runs schema validation tests from a JSON file against the ForTestSuiteschema implementation.
    54  func testJSONSchemaTestSuiteWithFilePath(t *testing.T, filePath string, exclusions ...string) {
    55  	t.Helper()
    56  
    57  	// Start the server
    58  	server := startTestServer()
    59  	defer stopTestServer(server)
    60  
    61  	// Read the JSON file containing the test definitions.
    62  	data, err := os.ReadFile(filePath) //nolint:gosec
    63  	if err != nil {
    64  		t.Fatalf("Failed to read test file: %s", err)
    65  	}
    66  
    67  	type Test struct {
    68  		Description string      `json:"description"`
    69  		Data        interface{} `json:"data"`
    70  		Valid       bool        `json:"valid"`
    71  	}
    72  	type TestCase struct {
    73  		Description string      `json:"description"`
    74  		SchemaData  interface{} `json:"schema"`
    75  		Tests       []Test      `json:"tests"`
    76  	}
    77  	var testCases []TestCase
    78  
    79  	// Unmarshal the JSON into the test cases struct.
    80  	if err := json.Unmarshal(data, &testCases); err != nil {
    81  		t.Fatalf("Failed to unmarshal test cases: %v", err)
    82  	}
    83  
    84  	exclusionMap := make(map[string]bool)
    85  	for _, exc := range exclusions {
    86  		exclusionMap[exc] = true
    87  	}
    88  
    89  	// Run each test case.
    90  	for _, tc := range testCases {
    91  		t.Run(tc.Description, func(t *testing.T) {
    92  			if exclusionMap[tc.Description] {
    93  				t.Skip("Skipping test case due to exclusion settings.")
    94  			}
    95  
    96  			// Convert schema data into JSON bytes and compile it into a Schema object.
    97  			schemaJSON, err := json.Marshal(tc.SchemaData)
    98  			if err != nil {
    99  				t.Fatalf("Failed to marshal schema data: %v", err)
   100  			}
   101  
   102  			// Initialize the compiler with necessary configurations.
   103  			compiler := jsonschema.NewCompiler()
   104  
   105  			// Assert format for optional/format test cases.
   106  			if strings.Contains(filePath, "optional/format") {
   107  				compiler.SetAssertFormat(true)
   108  			}
   109  
   110  			schema, err := compiler.Compile(schemaJSON)
   111  			if err != nil {
   112  				t.Fatalf("Failed to compile schema: %v", err)
   113  			}
   114  
   115  			for _, test := range tc.Tests {
   116  				if exclusionMap[tc.Description+"/"+test.Description] {
   117  					t.Run(test.Description, func(t *testing.T) {
   118  						t.Skip("Skipping test due to nested exclusion settings.")
   119  					})
   120  					continue
   121  				}
   122  				t.Run(test.Description, func(t *testing.T) {
   123  					// Evaluate the data against the schema.
   124  					result := schema.Validate(test.Data)
   125  
   126  					// Check if the test should pass or fail.
   127  					if test.Valid {
   128  						if !result.IsValid() {
   129  							t.Errorf("Expected data to be valid, but got error: %v", result.ToList())
   130  						}
   131  					} else {
   132  						if result.IsValid() {
   133  							t.Error("Expected data to be invalid, but got no error")
   134  						}
   135  					}
   136  				})
   137  			}
   138  		})
   139  	}
   140  }