lib_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. package xlsx
  2. import (
  3. "bytes"
  4. "encoding/xml"
  5. "strconv"
  6. "strings"
  7. "testing"
  8. )
  9. // Test we can correctly open a XSLX file and return a xlsx.File
  10. // struct.
  11. func TestOpenFile(t *testing.T) {
  12. var xlsxFile *File
  13. var error error
  14. xlsxFile, error = OpenFile("testfile.xlsx")
  15. if error != nil {
  16. t.Error(error.Error())
  17. return
  18. }
  19. if xlsxFile == nil {
  20. t.Error("OpenFile returned nil FileInterface without generating an os.Error")
  21. return
  22. }
  23. }
  24. // Test that when we open a real XLSX file we create xlsx.Sheet
  25. // objects for the sheets inside the file and that these sheets are
  26. // themselves correct.
  27. func TestCreateSheet(t *testing.T) {
  28. var xlsxFile *File
  29. var error error
  30. var sheet *Sheet
  31. var row *Row
  32. xlsxFile, error = OpenFile("testfile.xlsx")
  33. if error != nil {
  34. t.Error(error.Error())
  35. return
  36. }
  37. if xlsxFile == nil {
  38. t.Error("OpenFile returned a nil File pointer but did not generate an error.")
  39. return
  40. }
  41. sheetLen := len(xlsxFile.Sheets)
  42. if sheetLen == 0 {
  43. t.Error("Expected len(xlsxFile.Sheets) > 0, but got ", sheetLen)
  44. return
  45. }
  46. sheet = xlsxFile.Sheets[0]
  47. rowLen := len(sheet.Rows)
  48. if rowLen != 2 {
  49. t.Error("Expected len(sheet.Rows) == 2, but got ", rowLen)
  50. return
  51. }
  52. row = sheet.Rows[0]
  53. if len(row.Cells) != 2 {
  54. t.Error("Expected len(row.Cells) == 2")
  55. return
  56. }
  57. cell := row.Cells[0]
  58. cellstring := cell.String()
  59. if cellstring != "Foo" {
  60. t.Error("Expected cell.String() == 'Foo', got ", cellstring)
  61. }
  62. }
  63. // Test that we can correctly extract a reference table from the
  64. // sharedStrings.xml file embedded in the XLSX file and return a
  65. // reference table of string values from it.
  66. func TestReadSharedStringsFromZipFile(t *testing.T) {
  67. var xlsxFile *File
  68. var error error
  69. xlsxFile, error = OpenFile("testfile.xlsx")
  70. if error != nil {
  71. t.Error(error.Error())
  72. return
  73. }
  74. if xlsxFile.referenceTable == nil {
  75. t.Error("expected non nil xlsxFile.referenceTable")
  76. return
  77. }
  78. }
  79. func testXf(t *testing.T, result, expected *xlsxXf) {
  80. if result.ApplyAlignment != expected.ApplyAlignment {
  81. t.Error("Expected result.ApplyAlignment == ", expected.ApplyAlignment,
  82. ", got", result.ApplyAlignment)
  83. return
  84. }
  85. if result.ApplyBorder != expected.ApplyBorder {
  86. t.Error("Expected result.ApplyBorder == ", expected.ApplyBorder,
  87. ", got ", result.ApplyBorder)
  88. return
  89. }
  90. if result.ApplyFont != expected.ApplyFont {
  91. t.Error("Expect result.ApplyFont == ", expected.ApplyFont,
  92. ", got ", result.ApplyFont)
  93. return
  94. }
  95. if result.ApplyFill != expected.ApplyFill {
  96. t.Error("Expected result.ApplyFill == ", expected.ApplyFill,
  97. ", got ", result.ApplyFill)
  98. return
  99. }
  100. if result.ApplyProtection != expected.ApplyProtection {
  101. t.Error("Expexcted result.ApplyProtection == ", expected.ApplyProtection,
  102. ", got ", result.ApplyProtection)
  103. return
  104. }
  105. if result.BorderId != expected.BorderId {
  106. t.Error("Expected BorderId == ", expected.BorderId,
  107. ". got ", result.BorderId)
  108. return
  109. }
  110. if result.FillId != expected.FillId {
  111. t.Error("Expected result.FillId == ", expected.FillId,
  112. ", got ", result.FillId)
  113. return
  114. }
  115. if result.FontId != expected.FontId {
  116. t.Error("Expected result.FontId == ", expected.FontId,
  117. ", got ", result.FontId)
  118. return
  119. }
  120. if result.NumFmtId != expected.NumFmtId {
  121. t.Error("Expected result.NumFmtId == ", expected.NumFmtId,
  122. ", got ", result.NumFmtId)
  123. return
  124. }
  125. }
  126. // We can correctly extract a style table from the style.xml file
  127. // embedded in the XLSX file and return a styles struct from it.
  128. func TestReadStylesFromZipFile(t *testing.T) {
  129. var xlsxFile *File
  130. var error error
  131. var fontCount, fillCount, borderCount, cellStyleXfCount, cellXfCount int
  132. var font xlsxFont
  133. var fill xlsxFill
  134. var border xlsxBorder
  135. var xf xlsxXf
  136. xlsxFile, error = OpenFile("testfile.xlsx")
  137. if error != nil {
  138. t.Error(error.Error())
  139. return
  140. }
  141. if xlsxFile.styles == nil {
  142. t.Error("expected non nil xlsxFile.styles")
  143. return
  144. }
  145. fontCount = len(xlsxFile.styles.Fonts)
  146. if fontCount != 4 {
  147. t.Error("expected exactly 4 xslxFonts, got ", fontCount)
  148. return
  149. }
  150. font = xlsxFile.styles.Fonts[0]
  151. if font.Sz.Val != "11" {
  152. t.Error("expected font.Sz.Val == 11, got ", font.Sz.Val)
  153. return
  154. }
  155. if font.Name.Val != "Calibri" {
  156. t.Error("expected font.Name.Val == 'Calibri', got ", font.Name.Val)
  157. return
  158. }
  159. fillCount = len(xlsxFile.styles.Fills)
  160. if fillCount != 3 {
  161. t.Error("Expected exactly 3 xlsxFills, got ", fillCount)
  162. return
  163. }
  164. fill = xlsxFile.styles.Fills[2]
  165. if fill.PatternFill.PatternType != "solid" {
  166. t.Error("Expected PatternFill.PatternType == 'solid', but got ",
  167. fill.PatternFill.PatternType)
  168. return
  169. }
  170. borderCount = len(xlsxFile.styles.Borders)
  171. if borderCount != 2 {
  172. t.Error("Expected exactly 2 xlsxBorders, got ", borderCount)
  173. return
  174. }
  175. border = xlsxFile.styles.Borders[1]
  176. if border.Left.Style != "thin" {
  177. t.Error("Expected border.Left.Style == 'thin', got ", border.Left.Style)
  178. return
  179. }
  180. if border.Right.Style != "thin" {
  181. t.Error("Expected border.Right.Style == 'thin', got ", border.Right.Style)
  182. return
  183. }
  184. if border.Top.Style != "thin" {
  185. t.Error("Expected border.Top.Style == 'thin', got ", border.Top.Style)
  186. return
  187. }
  188. if border.Bottom.Style != "thin" {
  189. t.Error("Expected border.Bottom.Style == 'thin', got ", border.Bottom.Style)
  190. return
  191. }
  192. cellStyleXfCount = len(xlsxFile.styles.CellStyleXfs)
  193. if cellStyleXfCount != 20 {
  194. t.Error("Expected excactly 20 cellStyleXfs, got ", cellStyleXfCount)
  195. return
  196. }
  197. xf = xlsxFile.styles.CellStyleXfs[0]
  198. expectedXf := &xlsxXf{
  199. ApplyAlignment: true,
  200. ApplyBorder: true,
  201. ApplyFont: true,
  202. ApplyFill: false,
  203. ApplyProtection: true,
  204. BorderId: 0,
  205. FillId: 0,
  206. FontId: 0,
  207. NumFmtId: 164}
  208. testXf(t, &xf, expectedXf)
  209. cellXfCount = len(xlsxFile.styles.CellXfs)
  210. if cellXfCount != 3 {
  211. t.Error("Expected excactly 3 cellXfs, got ", cellXfCount)
  212. return
  213. }
  214. xf = xlsxFile.styles.CellXfs[0]
  215. expectedXf = &xlsxXf{
  216. ApplyAlignment: false,
  217. ApplyBorder: false,
  218. ApplyFont: false,
  219. ApplyFill: false,
  220. ApplyProtection: false,
  221. BorderId: 0,
  222. FillId: 0,
  223. FontId: 0,
  224. NumFmtId: 164}
  225. testXf(t, &xf, expectedXf)
  226. }
  227. func TestLettersToNumeric(t *testing.T) {
  228. cases := map[string]int{"A": 0, "G": 6, "z": 25, "AA": 26, "Az": 51,
  229. "BA": 52, "Bz": 77, "ZA": 26*26 + 0, "ZZ": 26*26 + 25,
  230. "AAA": 26*26 + 26 + 0, "AMI": 1022}
  231. for input, ans := range cases {
  232. output := lettersToNumeric(input)
  233. if output != ans {
  234. t.Error("Expected output '"+input+"' == ", ans,
  235. "but got ", strconv.Itoa(output))
  236. }
  237. }
  238. }
  239. func TestLetterOnlyMapFunction(t *testing.T) {
  240. var input string = "ABC123"
  241. var output string = strings.Map(letterOnlyMapF, input)
  242. if output != "ABC" {
  243. t.Error("Expected output == 'ABC' but got ", output)
  244. }
  245. input = "abc123"
  246. output = strings.Map(letterOnlyMapF, input)
  247. if output != "ABC" {
  248. t.Error("Expected output == 'ABC' but got ", output)
  249. }
  250. }
  251. func TestIntOnlyMapFunction(t *testing.T) {
  252. var input string = "ABC123"
  253. var output string = strings.Map(intOnlyMapF, input)
  254. if output != "123" {
  255. t.Error("Expected output == '123' but got ", output)
  256. }
  257. }
  258. func TestGetCoordsFromCellIDString(t *testing.T) {
  259. var cellIDString string = "A3"
  260. var x, y int
  261. var error error
  262. x, y, error = getCoordsFromCellIDString(cellIDString)
  263. if error != nil {
  264. t.Error(error)
  265. }
  266. if x != 0 {
  267. t.Error("Expected x == 0, but got ", strconv.Itoa(x))
  268. }
  269. if y != 2 {
  270. t.Error("Expected y == 2, but got ", strconv.Itoa(y))
  271. }
  272. }
  273. func TestGetMaxMinFromDimensionRef(t *testing.T) {
  274. var dimensionRef string = "A1:B2"
  275. var minx, miny, maxx, maxy int
  276. var err error
  277. minx, miny, maxx, maxy, err = getMaxMinFromDimensionRef(dimensionRef)
  278. if err != nil {
  279. t.Error(err)
  280. }
  281. if minx != 0 {
  282. t.Error("Expected minx == 0, but got ", strconv.Itoa(minx))
  283. }
  284. if miny != 0 {
  285. t.Error("Expected miny == 0, but got ", strconv.Itoa(miny))
  286. }
  287. if maxx != 1 {
  288. t.Error("Expected maxx == 0, but got ", strconv.Itoa(maxx))
  289. }
  290. if maxy != 1 {
  291. t.Error("Expected maxy == 0, but got ", strconv.Itoa(maxy))
  292. }
  293. }
  294. func TestGetRangeFromString(t *testing.T) {
  295. var rangeString string
  296. var lower, upper int
  297. var error error
  298. rangeString = "1:3"
  299. lower, upper, error = getRangeFromString(rangeString)
  300. if error != nil {
  301. t.Error(error)
  302. }
  303. if lower != 1 {
  304. t.Error("Expected lower bound == 1, but got ", strconv.Itoa(lower))
  305. }
  306. if upper != 3 {
  307. t.Error("Expected upper bound == 3, but got ", strconv.Itoa(upper))
  308. }
  309. }
  310. func TestMakeRowFromSpan(t *testing.T) {
  311. var rangeString string
  312. var row *Row
  313. var length int
  314. rangeString = "1:3"
  315. row = makeRowFromSpan(rangeString)
  316. length = len(row.Cells)
  317. if length != 3 {
  318. t.Error("Expected a row with 3 cells, but got ", strconv.Itoa(length))
  319. }
  320. rangeString = "5:7" // Note - we ignore lower bound!
  321. row = makeRowFromSpan(rangeString)
  322. length = len(row.Cells)
  323. if length != 7 {
  324. t.Error("Expected a row with 7 cells, but got ", strconv.Itoa(length))
  325. }
  326. rangeString = "1:1"
  327. row = makeRowFromSpan(rangeString)
  328. length = len(row.Cells)
  329. if length != 1 {
  330. t.Error("Expected a row with 1 cells, but got ", strconv.Itoa(length))
  331. }
  332. }
  333. func TestReadRowsFromSheet(t *testing.T) {
  334. var sharedstringsXML = bytes.NewBufferString(`
  335. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  336. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="4" uniqueCount="4">
  337. <si>
  338. <t>Foo</t>
  339. </si>
  340. <si>
  341. <t>Bar</t>
  342. </si>
  343. <si>
  344. <t xml:space="preserve">Baz </t>
  345. </si>
  346. <si>
  347. <t>Quuk</t>
  348. </si>
  349. </sst>`)
  350. var sheetxml = bytes.NewBufferString(`
  351. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  352. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  353. xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  354. <dimension ref="A1:B2"/>
  355. <sheetViews>
  356. <sheetView tabSelected="1" workbookViewId="0">
  357. <selection activeCell="C2" sqref="C2"/>
  358. </sheetView>
  359. </sheetViews>
  360. <sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
  361. <sheetData>
  362. <row r="1" spans="1:2">
  363. <c r="A1" t="s">
  364. <v>0</v>
  365. </c>
  366. <c r="B1" t="s">
  367. <v>1</v>
  368. </c>
  369. </row>
  370. <row r="2" spans="1:2">
  371. <c r="A2" t="s">
  372. <v>2</v>
  373. </c>
  374. <c r="B2" t="s">
  375. <v>3</v>
  376. </c>
  377. </row>
  378. </sheetData>
  379. <pageMargins left="0.7" right="0.7"
  380. top="0.78740157499999996"
  381. bottom="0.78740157499999996"
  382. header="0.3"
  383. footer="0.3"/>
  384. </worksheet>`)
  385. worksheet := new(xlsxWorksheet)
  386. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  387. if error != nil {
  388. t.Error(error.Error())
  389. return
  390. }
  391. sst := new(xlsxSST)
  392. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  393. if error != nil {
  394. t.Error(error.Error())
  395. return
  396. }
  397. file := new(File)
  398. file.referenceTable = MakeSharedStringRefTable(sst)
  399. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  400. if maxRows != 2 {
  401. t.Error("Expected maxRows == 2")
  402. }
  403. if maxCols != 2 {
  404. t.Error("Expected maxCols == 2")
  405. }
  406. row := rows[0]
  407. if len(row.Cells) != 2 {
  408. t.Error("Expected len(row.Cells) == 2, got ", strconv.Itoa(len(row.Cells)))
  409. }
  410. cell1 := row.Cells[0]
  411. if cell1.String() != "Foo" {
  412. t.Error("Expected cell1.String() == 'Foo', got ", cell1.String())
  413. }
  414. cell2 := row.Cells[1]
  415. if cell2.String() != "Bar" {
  416. t.Error("Expected cell2.String() == 'Bar', got ", cell2.String())
  417. }
  418. }
  419. func TestReadRowsFromSheetWithEmptyCells(t *testing.T) {
  420. var sharedstringsXML = bytes.NewBufferString(`
  421. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  422. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="8" uniqueCount="5"><si><t>Bob</t></si><si><t>Alice</t></si><si><t>Sue</t></si><si><t>Yes</t></si><si><t>No</t></si></sst>`)
  423. var sheetxml = bytes.NewBufferString(`
  424. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  425. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:C3"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"><selection activeCell="D3" sqref="D3"/></sheetView></sheetViews><sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
  426. <sheetData>
  427. <row r="1" spans="1:3">
  428. <c r="A1" t="s">
  429. <v>
  430. 0
  431. </v>
  432. </c>
  433. <c r="B1" t="s">
  434. <v>
  435. 1
  436. </v>
  437. </c>
  438. <c r="C1" t="s">
  439. <v>
  440. 2
  441. </v>
  442. </c>
  443. </row>
  444. <row r="2" spans="1:3">
  445. <c r="A2" t="s">
  446. <v>
  447. 3
  448. </v>
  449. </c>
  450. <c r="B2" t="s">
  451. <v>
  452. 4
  453. </v>
  454. </c>
  455. <c r="C2" t="s">
  456. <v>
  457. 3
  458. </v>
  459. </c>
  460. </row>
  461. <row r="3" spans="1:3">
  462. <c r="A3" t="s">
  463. <v>
  464. 4
  465. </v>
  466. </c>
  467. <c r="C3" t="s">
  468. <v>
  469. 3
  470. </v>
  471. </c>
  472. </row>
  473. </sheetData>
  474. <pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/>
  475. </worksheet>
  476. `)
  477. worksheet := new(xlsxWorksheet)
  478. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  479. if error != nil {
  480. t.Error(error.Error())
  481. return
  482. }
  483. sst := new(xlsxSST)
  484. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  485. if error != nil {
  486. t.Error(error.Error())
  487. return
  488. }
  489. file := new(File)
  490. file.referenceTable = MakeSharedStringRefTable(sst)
  491. rows, maxCols, maxRows := readRowsFromSheet(worksheet, file)
  492. if maxRows != 3 {
  493. t.Error("Expected maxRows == 3, got ", strconv.Itoa(len(rows)))
  494. }
  495. if maxCols != 3 {
  496. t.Error("Expected maxCols == 3, got ", strconv.Itoa(maxCols))
  497. }
  498. row := rows[2]
  499. if len(row.Cells) != 3 {
  500. t.Error("Expected len(row.Cells) == 3, got ", strconv.Itoa(len(row.Cells)))
  501. }
  502. cell1 := row.Cells[0]
  503. if cell1.String() != "No" {
  504. t.Error("Expected cell1.String() == 'No', got ", cell1.String())
  505. }
  506. cell2 := row.Cells[1]
  507. if cell2.String() != "" {
  508. t.Error("Expected cell2.String() == '', got ", cell2.String())
  509. }
  510. cell3 := row.Cells[2]
  511. if cell3.String() != "Yes" {
  512. t.Error("Expected cell3.String() == 'Yes', got ", cell3.String())
  513. }
  514. }
  515. func TestReadRowsFromSheetWithTrailingEmptyCells(t *testing.T) {
  516. var row *Row
  517. var cell1, cell2, cell3, cell4 *Cell
  518. var sharedstringsXML = bytes.NewBufferString(`
  519. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  520. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="4" uniqueCount="4"><si><t>A</t></si><si><t>B</t></si><si><t>C</t></si><si><t>D</t></si></sst>`)
  521. var sheetxml = bytes.NewBufferString(`
  522. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  523. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:D8"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"><selection activeCell="A7" sqref="A7"/></sheetView></sheetViews><sheetFormatPr baseColWidth="10" defaultRowHeight="15"/><sheetData><row r="1" spans="1:4"><c r="A1" t="s"><v>0</v></c><c r="B1" t="s"><v>1</v></c><c r="C1" t="s"><v>2</v></c><c r="D1" t="s"><v>3</v></c></row><row r="2" spans="1:4"><c r="A2"><v>1</v></c></row><row r="3" spans="1:4"><c r="B3"><v>1</v></c></row><row r="4" spans="1:4"><c r="C4"><v>1</v></c></row><row r="5" spans="1:4"><c r="D5"><v>1</v></c></row><row r="6" spans="1:4"><c r="C6"><v>1</v></c></row><row r="7" spans="1:4"><c r="B7"><v>1</v></c></row><row r="8" spans="1:4"><c r="A8"><v>1</v></c></row></sheetData><pageMargins left="0.7" right="0.7" top="0.78740157499999996" bottom="0.78740157499999996" header="0.3" footer="0.3"/></worksheet>
  524. `)
  525. worksheet := new(xlsxWorksheet)
  526. error := xml.NewDecoder(sheetxml).Decode(worksheet)
  527. if error != nil {
  528. t.Error(error.Error())
  529. return
  530. }
  531. sst := new(xlsxSST)
  532. error = xml.NewDecoder(sharedstringsXML).Decode(sst)
  533. if error != nil {
  534. t.Error(error.Error())
  535. return
  536. }
  537. file := new(File)
  538. file.referenceTable = MakeSharedStringRefTable(sst)
  539. rows, maxCol, maxRow := readRowsFromSheet(worksheet, file)
  540. if maxCol != 4 {
  541. t.Error("Expected maxCol == 4, got ", strconv.Itoa(maxCol))
  542. }
  543. if maxRow != 8 {
  544. t.Error("Expected maxRow == 8, got ", strconv.Itoa(maxRow))
  545. }
  546. row = rows[0]
  547. if len(row.Cells) != 4 {
  548. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  549. }
  550. cell1 = row.Cells[0]
  551. if cell1.String() != "A" {
  552. t.Error("Expected cell1.String() == 'A', got ", cell1.String())
  553. }
  554. cell2 = row.Cells[1]
  555. if cell2.String() != "B" {
  556. t.Error("Expected cell2.String() == 'B', got ", cell2.String())
  557. }
  558. cell3 = row.Cells[2]
  559. if cell3.String() != "C" {
  560. t.Error("Expected cell3.String() == 'C', got ", cell3.String())
  561. }
  562. cell4 = row.Cells[3]
  563. if cell4.String() != "D" {
  564. t.Error("Expected cell4.String() == 'D', got ", cell4.String())
  565. }
  566. row = rows[1]
  567. if len(row.Cells) != 4 {
  568. t.Error("Expected len(row.Cells) == 4, got ", strconv.Itoa(len(row.Cells)))
  569. }
  570. cell1 = row.Cells[0]
  571. if cell1.String() != "1" {
  572. t.Error("Expected cell1.String() == '1', got ", cell1.String())
  573. }
  574. cell2 = row.Cells[1]
  575. if cell2.String() != "" {
  576. t.Error("Expected cell2.String() == '', got ", cell2.String())
  577. }
  578. cell3 = row.Cells[2]
  579. if cell3.String() != "" {
  580. t.Error("Expected cell3.String() == '', got ", cell3.String())
  581. }
  582. cell4 = row.Cells[3]
  583. if cell4.String() != "" {
  584. t.Error("Expected cell4.String() == '', got ", cell4.String())
  585. }
  586. }