Skip to content

Commit 687e5df

Browse files
authored
Merge pull request #256 from carlosms/uast-empty-str
Fix UAST unmarshal for empty strings
2 parents d87eb2a + 9291e08 commit 687e5df

5 files changed

Lines changed: 86 additions & 3 deletions

File tree

server/handler/export.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func Export(db service.SQLDB) http.HandlerFunc {
7878
if sqlVal.Valid {
7979
nodes, err := service.UnmarshalUAST([]byte(sqlVal.String))
8080

81-
if err == nil {
81+
if err == nil && nodes != nil {
8282
b, err := json.Marshal(nodes)
8383
if err != nil {
8484
return err

server/handler/export_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package handler_test
22

33
import (
4+
"encoding/csv"
45
"fmt"
56
"net/http"
67
"net/http/httptest"
78
"testing"
89

910
"github.com/src-d/gitbase-web/server/handler"
1011
"github.com/src-d/gitbase-web/server/service"
12+
common "github.com/src-d/gitbase-web/server/testing"
13+
1114
"github.com/stretchr/testify/assert"
1215
"github.com/stretchr/testify/suite"
1316
sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
@@ -55,6 +58,45 @@ func (suite *ExportSuite) TestSuccess() {
5558
suite.Equal(http.StatusOK, res.Code)
5659
}
5760

61+
func (suite *ExportSuite) TestSuccessUAST() {
62+
rows := sqlmock.NewRows([]string{"a", "b", "uast"}).
63+
AddRow(1, "one", common.UASTMarshaled).
64+
AddRow(2, "two", "")
65+
66+
suite.mock.ExpectQuery(".*").WillReturnRows(rows)
67+
68+
req, _ := http.NewRequest("GET", "/export/?query=select+*+from+repositories", nil)
69+
res := httptest.NewRecorder()
70+
71+
suite.handler.ServeHTTP(res, req)
72+
suite.Equal(http.StatusOK, res.Code)
73+
74+
r := csv.NewReader(res.Body)
75+
76+
expected := [][]string{
77+
[]string{
78+
"a",
79+
"b",
80+
"uast",
81+
},
82+
[]string{
83+
"1",
84+
"one",
85+
common.UASTMarshaledJSON,
86+
},
87+
[]string{
88+
"2",
89+
"two",
90+
"",
91+
},
92+
}
93+
94+
records, err := r.ReadAll()
95+
suite.Require().Nil(err)
96+
suite.Require().Equal(expected, records)
97+
98+
}
99+
58100
func (suite *ExportSuite) TestDBError() {
59101
suite.mock.ExpectQuery(".*").WillReturnError(fmt.Errorf("forced err"))
60102

server/handler/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func columnsData(
160160
sqlVal, _ := val.(*sql.NullString)
161161
if sqlVal.Valid {
162162
nodes, err := service.UnmarshalUAST([]byte(sqlVal.String))
163-
if err == nil {
163+
if err == nil && nodes != nil {
164164
colData[columnNames[i]] = nodes
165165
colData["__"+columnNames[i]+"-protobufs"] = []byte(sqlVal.String)
166166
} else {

server/handler/query_test.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/src-d/gitbase-web/server/service"
14+
common "github.com/src-d/gitbase-web/server/testing"
15+
1316
"github.com/pressly/lg"
1417
"github.com/stretchr/testify/assert"
1518
"github.com/stretchr/testify/suite"
@@ -116,7 +119,7 @@ func (suite *QuerySuite) TestTypes() {
116119

117120
columnValsPtr := genericVals(columnTypes)
118121

119-
mockRows := sqlmock.NewRows([]string{"a", "b", "c", "d"}).
122+
mockRows := sqlmock.NewRows(columnNames).
120123
AddRow(1, 1234, 1.56, "value").
121124
AddRow(nil, nil, nil, nil)
122125

@@ -150,6 +153,38 @@ func (suite *QuerySuite) TestTypes() {
150153
suite.Nil(colData["d"])
151154
}
152155

156+
func (suite *QuerySuite) TestUASTType() {
157+
columnNames := []string{"filename", "uast_a", "uast_b"}
158+
columnTypes := []string{"TEXT", "TEXT", "TEXT"}
159+
160+
columnValsPtr := genericVals(columnTypes)
161+
162+
mockRows := sqlmock.NewRows(columnNames).
163+
AddRow("hello.js", "", common.UASTMarshaled)
164+
165+
suite.mock.ExpectQuery(".*").WillReturnRows(mockRows)
166+
167+
rows, err := suite.db.Query("select * from table")
168+
suite.NoError(err)
169+
170+
rows.Next()
171+
err = rows.Scan(columnValsPtr...)
172+
suite.NoError(err)
173+
174+
colData, err := columnsData(columnNames, columnTypes, columnValsPtr)
175+
suite.NoError(err)
176+
177+
suite.EqualValues("hello.js", colData["filename"])
178+
suite.Nil(colData["__filename-protobufs"])
179+
180+
suite.EqualValues("", colData["uast_a"])
181+
suite.Nil(colData["__uast_a-protobufs"])
182+
183+
var nodeArr []*service.Node
184+
suite.IsType(nodeArr, colData["uast_b"])
185+
suite.EqualValues(common.UASTMarshaled, colData["__uast_b-protobufs"])
186+
}
187+
153188
func (suite *QuerySuite) TestQueryAbort() {
154189
// Ideally we would test that the sql query context is canceled, but
155190
// go-sqlmock does not have something like ExpectContextCancellation

server/testing/common.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,9 @@ func (db *MockDB) QueryContext(ctx context.Context, query string, args ...interf
3232
func (db *MockDB) QueryRow(query string, args ...interface{}) *sql.Row {
3333
return nil
3434
}
35+
36+
// As returned by gitbase v0.17.0-rc.4, SELECT UAST('console.log("test")', 'JavaScript') AS uast
37+
const (
38+
UASTMarshaled = "\x00\x00\x02\x16\n\x04File\x1a\xfc\x03\n\aProgram\x12\x17\n\finternalRole\x12\aprogram\x12\x14\n\nsourceType\x12\x06module\x1a\xb0\x03\n\x13ExpressionStatement\x12\x14\n\finternalRole\x12\x04body\x1a\xf1\x02\n\x0eCallExpression\x12\x1a\n\finternalRole\x12\nexpression\x1a\xdc\x01\n\x10MemberExpression\x12\x16\n\finternalRole\x12\x06callee\x12\x11\n\bcomputed\x12\x05false\x1aC\n\nIdentifier\x12\x16\n\finternalRole\x12\x06object\x12\x0f\n\x04Name\x12\aconsole*\x04\x10\x01\x18\x012\x06\b\a\x10\x01\x18\b\x1aC\n\nIdentifier\x12\v\n\x04Name\x12\x03log\x12\x18\n\finternalRole\x12\bproperty*\x06\b\b\x10\x01\x18\t2\x06\b\v\x10\x01\x18\f*\x04\x10\x01\x18\x012\x06\b\v\x10\x01\x18\f:\x05\x02\x12\x01TU\x1aR\n\x06String\x12\r\n\x05Value\x12\x04test\x12\n\n\x06Format\x12\x00\x12\x19\n\finternalRole\x12\targuments*\x06\b\f\x10\x01\x18\r2\x06\b\x12\x10\x01\x18\x13:\x02T1*\x04\x10\x01\x18\x012\x06\b\x13\x10\x01\x18\x14:\x02\x12T*\x04\x10\x01\x18\x012\x06\b\x13\x10\x01\x18\x14:\x01\x13*\x04\x10\x01\x18\x012\x06\b\x13\x10\x01\x18\x14:\x019*\x04\x10\x01\x18\x012\x06\b\x13\x10\x01\x18\x14:\x01\""
39+
UASTMarshaledJSON = "[{\"InternalType\":\"File\",\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":19,\"Line\":1,\"Col\":20},\"Roles\":[\"Unannotated\",\"File\"],\"Children\":[{\"InternalType\":\"Program\",\"Properties\":{\"internalRole\":\"program\",\"sourceType\":\"module\"},\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":19,\"Line\":1,\"Col\":20},\"Roles\":[\"Module\"],\"Children\":[{\"InternalType\":\"ExpressionStatement\",\"Properties\":{\"internalRole\":\"body\"},\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":19,\"Line\":1,\"Col\":20},\"Roles\":[\"Statement\"],\"Children\":[{\"InternalType\":\"CallExpression\",\"Properties\":{\"internalRole\":\"expression\"},\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":19,\"Line\":1,\"Col\":20},\"Roles\":[\"Expression\",\"Call\"],\"Children\":[{\"InternalType\":\"MemberExpression\",\"Properties\":{\"computed\":\"false\",\"internalRole\":\"callee\"},\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":11,\"Line\":1,\"Col\":12},\"Roles\":[\"Qualified\",\"Expression\",\"Identifier\",\"Call\",\"Callee\"],\"Children\":[{\"InternalType\":\"Identifier\",\"Properties\":{\"Name\":\"console\",\"internalRole\":\"object\"},\"StartPosition\":{\"Offset\":0,\"Line\":1,\"Col\":1},\"EndPosition\":{\"Offset\":7,\"Line\":1,\"Col\":8},\"Roles\":[],\"Children\":[]},{\"InternalType\":\"Identifier\",\"Properties\":{\"Name\":\"log\",\"internalRole\":\"property\"},\"StartPosition\":{\"Offset\":8,\"Line\":1,\"Col\":9},\"EndPosition\":{\"Offset\":11,\"Line\":1,\"Col\":12},\"Roles\":[],\"Children\":[]}]},{\"InternalType\":\"String\",\"Properties\":{\"Format\":\"\",\"Value\":\"test\",\"internalRole\":\"arguments\"},\"StartPosition\":{\"Offset\":12,\"Line\":1,\"Col\":13},\"EndPosition\":{\"Offset\":18,\"Line\":1,\"Col\":19},\"Roles\":[\"Call\",\"Argument\"],\"Children\":[]}]}]}]}]}]"
40+
)

0 commit comments

Comments
 (0)