package browse import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // The nulls fixture table, in primary-key order. note is a real NULL at id=2 // and id=5, and the literal four-character string "NULL" at id=3. // // id | note // 1 | 'alpha' // 2 | NULL // 3 | 'NULL' // 4 | 'delta' // 5 | NULL // 6 | 'zeta' // TestRowsNullMaskSeparatesStoredNULLText is the whole point of the mask: the // rendered strings of a real NULL and of a stored "NULL" are equal, and only // Nulls tells a caller which is which. func TestRowsNullMaskSeparatesStoredNULLText(t *testing.T) { db := openFixture(t) ctx := context.Background() page, err := db.Rows(ctx, "main", "nulls", 0, 4) require.NoError(t, err) require.Len(t, page.Rows, 4) require.Equal(t, []string{"id", "note"}, page.Columns) realNull := page.Rows[1] // id=2 storedText := page.Rows[2] // id=3 assert.Equal(t, placeholderNull, realNull[1]) assert.Equal(t, placeholderNull, storedText[1]) assert.Equal(t, realNull[1], storedText[1], "both must still render identically; the rendered strings are not allowed to change") require.Len(t, page.Nulls, len(page.Rows)) assert.True(t, page.Nulls[1][1], "id=2 stores no value: the mask must say so") assert.False(t, page.Nulls[2][1], "id=3 stores the text \"NULL\": the mask must not claim it is null") // Ordinary values and primary keys are never null. assert.False(t, page.Nulls[0][0]) assert.False(t, page.Nulls[0][1]) assert.False(t, page.Nulls[1][0], "a primary key cannot be null") assert.False(t, page.Nulls[3][1]) } // TestRowsNullMaskAllFalseWhenPopulated: a table with no NULL in it yields a // mask that is present, correctly shaped, and entirely false. func TestRowsNullMaskAllFalseWhenPopulated(t *testing.T) { db := openFixture(t) ctx := context.Background() page, err := db.Rows(ctx, "main", "users", 0, 10) require.NoError(t, err) require.Len(t, page.Rows, 4) require.Len(t, page.Nulls, len(page.Rows)) for i, mask := range page.Nulls { for j, isNull := range mask { assert.Falsef(t, isNull, "users row %d cell %d (%q) must not be null", i, j, page.Rows[i][j]) } } } // TestRowsNullMaskShape: every mask row is as long as its row, which is as long // as Columns — so a caller may index Nulls with any index valid for Rows. func TestRowsNullMaskShape(t *testing.T) { db := openFixture(t) ctx := context.Background() for _, table := range []string{"users", "nulls", "docs", "items"} { page, err := db.Rows(ctx, "main", table, 0, 10) require.NoErrorf(t, err, "table %q", table) require.Lenf(t, page.Nulls, len(page.Rows), "table %q: one mask per row", table) for i := range page.Rows { assert.Lenf(t, page.Nulls[i], len(page.Rows[i]), "table %q row %d: mask width must equal row width", table, i) assert.Lenf(t, page.Nulls[i], len(page.Columns), "table %q row %d: mask width must equal column count", table, i) } } } // TestRowsNullMaskPagingAlignment reads a page that neither starts at the first // row nor ends at the last one: an off-by-one between the mask and the rows // would show up here and nowhere else. func TestRowsNullMaskPagingAlignment(t *testing.T) { db := openFixture(t) ctx := context.Background() // Rows 3, 4, 5 of six: stored "NULL", 'delta', real NULL. page, err := db.Rows(ctx, "main", "nulls", 2, 3) require.NoError(t, err) require.Equal(t, 2, page.Offset) require.Equal(t, 6, page.Total) require.Equal(t, [][]string{ {"3", placeholderNull}, {"4", "delta"}, {"5", placeholderNull}, }, page.Rows) assert.Equal(t, [][]bool{ {false, false}, {false, false}, {false, true}, }, page.Nulls, "the mask must be aligned with the rows this page actually returned") // A page past the end has no rows and therefore no mask rows. past, err := db.Rows(ctx, "main", "nulls", 6, 3) require.NoError(t, err) assert.Empty(t, past.Rows) assert.Empty(t, past.Nulls) }