github.com/arr-ai/arrai@v0.319.0/pkg/test/runner_test.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package test
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"os"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/arr-ai/arrai/pkg/ctxfs"
    15  	"github.com/arr-ai/arrai/pkg/ctxrootcache"
    16  )
    17  
    18  func TestRunTests_Pass(t *testing.T) {
    19  	t.Parallel()
    20  
    21  	fsContent := map[string]string{"/test/1_test.arrai": "(test1: 1 = 1)"}
    22  	buf := &bytes.Buffer{}
    23  	err := RunTests(withFs(t, fsContent), buf, "/test")
    24  
    25  	require.NoError(t, err)
    26  	shouldContain(t, buf.String(), "PASS", "test1")
    27  }
    28  
    29  func TestRunTests_EmptyPath(t *testing.T) {
    30  	t.Parallel()
    31  
    32  	fsContent := map[string]string{"/test/1_test.arrai": "(test1: 1 = 1)"}
    33  	buf := &bytes.Buffer{}
    34  	err := RunTests(withFs(t, fsContent), buf, "")
    35  
    36  	require.NoError(t, err)
    37  	shouldContain(t, buf.String(), "PASS", "test1")
    38  }
    39  
    40  func TestRunTests_Fail(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	fsContent := map[string]string{"/test/1_test.arrai": "(test1: 1 = 1, test2: 2 = 3)"}
    44  	buf := &bytes.Buffer{}
    45  	err := RunTests(withFs(t, fsContent), buf, "/test")
    46  
    47  	require.Error(t, err)
    48  	shouldContain(t, buf.String(), "PASS", "test1", "FAIL", "test2")
    49  }
    50  
    51  func TestRunTests_Invalid(t *testing.T) {
    52  	t.Parallel()
    53  
    54  	fsContent := map[string]string{"/test/1_test.arrai": "(test1: 1 = 1, test2: 2)"}
    55  	buf := &bytes.Buffer{}
    56  	err := RunTests(withFs(t, fsContent), buf, "/test")
    57  
    58  	require.Error(t, err)
    59  	shouldContain(t, buf.String(), "PASS", "test1", "??", "test2")
    60  }
    61  
    62  func TestRunTests_BadArrai(t *testing.T) {
    63  	t.Parallel()
    64  
    65  	fsContent := map[string]string{"/test/1_test.arrai": "x"}
    66  	buf := &bytes.Buffer{}
    67  	err := RunTests(withFs(t, fsContent), buf, "/test")
    68  
    69  	require.Error(t, err)
    70  }
    71  
    72  func TestRunTests_InvalidDir(t *testing.T) {
    73  	t.Parallel()
    74  
    75  	fsContent := map[string]string{}
    76  	buf := &bytes.Buffer{}
    77  	err := RunTests(withFs(t, fsContent), buf, "/nowhere")
    78  
    79  	require.Error(t, err)
    80  }
    81  
    82  func TestGetTestFiles_NoFiles(t *testing.T) {
    83  	t.Parallel()
    84  
    85  	fsContent := map[string]string{"/test/placeholder.txt": ""}
    86  	_, err := getTestFiles(withFs(t, fsContent), "/test")
    87  	require.Error(t, err)
    88  }
    89  
    90  func TestGetTestFiles_InvalidDir(t *testing.T) {
    91  	t.Parallel()
    92  
    93  	fsContent := map[string]string{"/test/placeholder.txt": ""}
    94  	_, err := getTestFiles(withFs(t, fsContent), "/nowhere")
    95  	require.Error(t, err)
    96  }
    97  
    98  func TestGetTestFiles_OneFile(t *testing.T) {
    99  	t.Parallel()
   100  
   101  	fsContent := map[string]string{"/test/1_test.arrai": "source1"}
   102  	files, err := getTestFiles(withFs(t, fsContent), "/test")
   103  	require.NoError(t, err)
   104  	require.Equal(t, []File{{Path: "/test/1_test.arrai", Source: "source1"}}, files)
   105  }
   106  
   107  func TestGetTestFiles_PathIsFile(t *testing.T) {
   108  	t.Parallel()
   109  
   110  	fsContent := map[string]string{
   111  		"/test/1_test.arrai": "source1",
   112  		"/test/2_test.arrai": "source2",
   113  	}
   114  	files, err := getTestFiles(withFs(t, fsContent), "/test/1_test.arrai")
   115  	require.NoError(t, err)
   116  	require.Equal(t, []File{{Path: "/test/1_test.arrai", Source: "source1"}}, files)
   117  }
   118  
   119  func TestGetTestFiles_NestedDir(t *testing.T) {
   120  	t.Parallel()
   121  
   122  	fsContent := map[string]string{
   123  		"/test/1_test.arrai":                "source1",
   124  		"/test/must/go/deeper/2_test.arrai": "source2",
   125  	}
   126  	files, err := getTestFiles(withFs(t, fsContent), "/test")
   127  	require.NoError(t, err)
   128  	require.Equal(t, []File{
   129  		{Path: "/test/1_test.arrai", Source: "source1"},
   130  		{Path: "/test/must/go/deeper/2_test.arrai", Source: "source2"},
   131  	}, files)
   132  }
   133  
   134  func TestGetTestFiles_SkipHiddenDir(t *testing.T) {
   135  	t.Parallel()
   136  
   137  	fsContent := map[string]string{
   138  		"/test/1_test.arrai":                 "source1",
   139  		"/test/.must/go/deeper/2_test.arrai": "source2",
   140  		"/test/must/.go/deeper/3_test.arrai": "source3",
   141  		"/test/must/go/.deeper/4_test.arrai": "source4",
   142  	}
   143  	files, err := getTestFiles(withFs(t, fsContent), "/test")
   144  	require.NoError(t, err)
   145  	require.Equal(t, []File{{Path: "/test/1_test.arrai", Source: "source1"}}, files)
   146  }
   147  
   148  func withFs(t *testing.T, files map[string]string) context.Context {
   149  	err := os.Chdir("/")
   150  	require.NoError(t, err)
   151  	fs := ctxfs.CreateTestMemMapFs(t, files)
   152  	ctx := ctxfs.SourceFsOnto(context.Background(), fs)
   153  	return ctxrootcache.WithRootCache(ctx)
   154  }
   155  
   156  func TestRunFile_InvalidArrai(t *testing.T) {
   157  	t.Parallel()
   158  
   159  	file := File{Source: "invalid arr.ai code"}
   160  	err := runFile(context.Background(), &file)
   161  	require.Error(t, err)
   162  }
   163  
   164  func TestRunFile_AssertFails(t *testing.T) {
   165  	t.Parallel()
   166  
   167  	file := File{Source: "//test.assert.equal(1, 2)"}
   168  	err := runFile(context.Background(), &file)
   169  	require.Error(t, err)
   170  }
   171  
   172  func TestRunFile_TwoPass(t *testing.T) {
   173  	t.Parallel()
   174  
   175  	file := File{Source: "(test1: 1 = 1, test2: //test.assert.equal(2, 2))"}
   176  	err := runFile(context.Background(), &file)
   177  	require.NoError(t, err)
   178  	require.NotZero(t, file.WallTime)
   179  	require.ElementsMatch(t, file.Results, []Result{
   180  		{Name: "test1", Outcome: Passed},
   181  		{Name: "test2", Outcome: Passed}})
   182  }
   183  
   184  func TestRunFile_OneFailOnePass(t *testing.T) {
   185  	t.Parallel()
   186  
   187  	file := File{Source: "(test1: 1 < 1, test2: 5 < 7)"}
   188  	err := runFile(context.Background(), &file)
   189  	require.NoError(t, err)
   190  	require.NotZero(t, file.WallTime)
   191  	require.ElementsMatch(t, file.Results, []Result{
   192  		{Name: "test1", Outcome: Failed, Message: "Expected: true. Actual: false."},
   193  		{Name: "test2", Outcome: Passed}})
   194  }
   195  
   196  func TestRunFile_OneInvalidOnePass(t *testing.T) {
   197  	t.Parallel()
   198  
   199  	file := File{Source: "(test1: 1, test2: 5 < 7)"}
   200  	err := runFile(context.Background(), &file)
   201  	require.NoError(t, err)
   202  	require.NotZero(t, file.WallTime)
   203  	require.ElementsMatch(t, file.Results, []Result{
   204  		{Name: "test1", Outcome: Invalid,
   205  			Message: "Could not determine test Outcome due to non-boolean result of type number: 1"},
   206  		{Name: "test2", Outcome: Passed}})
   207  }
   208  
   209  func TestRunFile_TestInSet(t *testing.T) {
   210  	t.Parallel()
   211  
   212  	file := File{
   213  		Path:   "some_test.arrai",
   214  		Source: "(test1: 1 = 1, category1: { 5 < 7 })",
   215  	}
   216  	err := runFile(context.Background(), &file)
   217  	require.NoError(t, err)
   218  	require.NotZero(t, file.WallTime)
   219  	require.ElementsMatch(t, file.Results, []Result{
   220  		{Name: "test1", Outcome: Passed},
   221  		{Name: "category1", Outcome: Invalid, Message: "Sets are not allowed as test containers. " +
   222  			"Please use tuples, dictionaries or arrays."}})
   223  }