// Copyright 2024 Matthew Rich . All rights reserved. package folio import ( "fmt" "github.com/stretchr/testify/assert" "path/filepath" "strings" "testing" "decl/internal/data" "decl/internal/codec" "decl/internal/types" "io" "log/slog" ) var ( TestResourceTypes *types.Types[data.Resource] = types.New[data.Resource]() TestConfigurationTypes *types.Types[data.Configuration] = types.New[data.Configuration]() TestConverterTypes *types.Types[data.Converter] = types.New[data.Converter]() ) func TestNewDocument(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes d := NewDocument(nil) assert.NotNil(t, d) } func TestDocumentInterface(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes var doc data.Document = NewDocument(nil) assert.NotNil(t, doc) } func TestDocumentLoader(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes slog.Info("TestDocumentLoader", "rt", TestResourceTypes) file, _ := filepath.Abs(TempDir.FilePath("foo.txt")) document := fmt.Sprintf(` --- resources: - type: foo attributes: name: "%s" size: %d - type: bar attributes: name: "testbar" size: %d `, file, 55, 11) d := NewDocument(nil) assert.NotNil(t, d) assert.Equal(t, TestResourceTypes, d.Types()) docReader := io.NopCloser(strings.NewReader(document)) e := d.LoadReader(docReader, codec.FormatYaml) assert.Nil(t, e) resources := d.Resources() assert.Equal(t, 2, len(resources)) } func TestDocumentGenerator(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes f := NewFooResource() assert.NotNil(t, f) expected := fmt.Sprintf(` format: yaml resources: - type: foo attributes: name: %s size: %d `, "mytestresource", 3) var documentYaml strings.Builder d := NewDocument(nil) assert.NotNil(t, d) f.Name = "mytestresource" f.Size = 3 assert.Nil(t, f.Init(nil)) d.AddResourceDeclaration("foo", f) ey := d.Generate(&documentYaml) assert.Nil(t, ey) assert.Greater(t, documentYaml.Len(), 0) assert.YAMLEq(t, expected, documentYaml.String()) } func TestDocumentAddResource(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes d := NewDocument(nil) assert.NotNil(t, d) e := d.AddResource("foo://bar") assert.Nil(t, e) } func TestDocumentJSON(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes document := ` --- resources: - type: foo attributes: name: "testfoo" size: 10022 ` d := NewDocument(nil) assert.NotNil(t, d) docReader := io.NopCloser(strings.NewReader(document)) e := d.LoadReader(docReader, codec.FormatYaml) assert.Nil(t, e) marshalledJSON, jsonErr := d.JSON() assert.Nil(t, jsonErr) assert.Greater(t, len(marshalledJSON), 0) } func TestDocumentJSONSchema(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes document := NewDocument(nil) document.ResourceDeclarations = []*Declaration{} e := document.Validate() assert.Nil(t, e) f := NewFooResource() assert.NotNil(t, f) f.Name = "mytestresource" f.Size = 3 document.AddResourceDeclaration("foo", f) resourceErr := document.Validate() assert.ErrorContains(t, resourceErr, "Must be greater than or equal to 5") f.Size = 7 b := NewBarResource() assert.NotNil(t, b) b.Name = "testbarresource" b.Size = 3 b.Owner = "a" document.AddResourceDeclaration("bar", b) assert.ErrorContains(t, document.Validate(), "String length must be greater than or equal to 3") } func TestDocumentYAML(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes document := ` --- format: yaml resources: - type: testuser attributes: name: "foo" uid: "10022" group: "10022" home: "/home/foo" ` d := NewDocument(nil) assert.NotNil(t, d) docReader := io.NopCloser(strings.NewReader(document)) e := d.LoadReader(docReader, codec.FormatYaml) assert.Nil(t, e) marshalledYAML, yamlErr := d.YAML() assert.Nil(t, yamlErr) assert.YAMLEq(t, string(document), string(marshalledYAML)) } func TestDocumentResourceFilter(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes document := ` --- resources: - type: testuser attributes: name: "testuser" uid: "10022" home: "/home/testuser" - type: foo attributes: name: "foo.txt" - type: bar attributes: name: "bar.txt" ` d := NewDocument(nil) assert.NotNil(t, d) docReader := io.NopCloser(strings.NewReader(document)) e := d.LoadReader(docReader, codec.FormatYaml) assert.Nil(t, e) resources := d.Filter(func(d data.Declaration) bool { return d.ResourceType() == "foo" }) assert.Equal(t, 1, len(resources)) } func TestDocumentImports(t *testing.T) { DocumentRegistry.ResourceTypes = TestResourceTypes DocumentRegistry.ConverterTypes = TestConverterTypes cycleDocPath := TempDir.FilePath("cycle.jx.yaml") srcDoc := fmt.Sprintf(` imports: - %s resources: - type: testuser attributes: name: "testuser" uid: "10022" home: "/home/testuser" `, cycleDocPath) srcDocPath, err := TempDir.CreateFileFromReader("src.jx.yaml", strings.NewReader(srcDoc)) assert.Nil(t, err) srcDocPathURI := fmt.Sprintf("file://%s", srcDocPath) document := fmt.Sprintf(` --- imports: - %s resources: - type: foo attributes: name: "foo.txt" - type: bar attributes: name: "bar.txt" `, srcDocPathURI) docPath, err := TempDir.CreateFileFromReader("doc.jx.yaml", strings.NewReader(document)) assert.Nil(t, err) docPathURI := fmt.Sprintf("file://%s", docPath) cycle := fmt.Sprintf(` --- imports: - %s - %s resources: - type: foo attributes: name: "foo2.txt" `, srcDocPathURI, docPathURI) _, err = TempDir.CreateFileFromReader("cycle.jx.yaml", strings.NewReader(cycle)) assert.Nil(t, err) cycleDocPathURI := fmt.Sprintf("file://%s", cycleDocPath) _, loadErr := DocumentRegistry.Load(URI(docPathURI)) assert.Nil(t, loadErr) assert.True(t, DocumentRegistry.HasDocument(URI(srcDocPathURI))) assert.True(t, DocumentRegistry.HasDocument(URI(cycleDocPathURI))) }