cell_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. package xlsx
  2. import (
  3. "math"
  4. "testing"
  5. "time"
  6. . "gopkg.in/check.v1"
  7. )
  8. type CellSuite struct{}
  9. var _ = Suite(&CellSuite{})
  10. // Test that we can set and get a Value from a Cell
  11. func (s *CellSuite) TestValueSet(c *C) {
  12. // Note, this test is fairly pointless, it serves mostly to
  13. // reinforce that this functionality is important, and should
  14. // the mechanics of this all change at some point, to remind
  15. // us not to lose this.
  16. cell := Cell{}
  17. cell.Value = "A string"
  18. c.Assert(cell.Value, Equals, "A string")
  19. }
  20. // Test that GetStyle correctly converts the xlsxStyle.Fonts.
  21. func (s *CellSuite) TestGetStyleWithFonts(c *C) {
  22. font := NewFont(10, "Calibra")
  23. style := NewStyle()
  24. style.Font = *font
  25. cell := &Cell{Value: "123", style: style}
  26. style = cell.GetStyle()
  27. c.Assert(style, NotNil)
  28. c.Assert(style.Font.Size, Equals, 10)
  29. c.Assert(style.Font.Name, Equals, "Calibra")
  30. }
  31. // Test that SetStyle correctly translates into a xlsxFont element
  32. func (s *CellSuite) TestSetStyleWithFonts(c *C) {
  33. file := NewFile()
  34. sheet, _ := file.AddSheet("Test")
  35. row := sheet.AddRow()
  36. cell := row.AddCell()
  37. font := NewFont(12, "Calibra")
  38. style := NewStyle()
  39. style.Font = *font
  40. cell.SetStyle(style)
  41. style = cell.GetStyle()
  42. xFont, _, _, _ := style.makeXLSXStyleElements()
  43. c.Assert(xFont.Sz.Val, Equals, "12")
  44. c.Assert(xFont.Name.Val, Equals, "Calibra")
  45. }
  46. // Test that GetStyle correctly converts the xlsxStyle.Fills.
  47. func (s *CellSuite) TestGetStyleWithFills(c *C) {
  48. fill := *NewFill("solid", "FF000000", "00FF0000")
  49. style := NewStyle()
  50. style.Fill = fill
  51. cell := &Cell{Value: "123", style: style}
  52. style = cell.GetStyle()
  53. _, xFill, _, _ := style.makeXLSXStyleElements()
  54. c.Assert(xFill.PatternFill.PatternType, Equals, "solid")
  55. c.Assert(xFill.PatternFill.BgColor.RGB, Equals, "00FF0000")
  56. c.Assert(xFill.PatternFill.FgColor.RGB, Equals, "FF000000")
  57. }
  58. // Test that SetStyle correctly updates xlsxStyle.Fills.
  59. func (s *CellSuite) TestSetStyleWithFills(c *C) {
  60. file := NewFile()
  61. sheet, _ := file.AddSheet("Test")
  62. row := sheet.AddRow()
  63. cell := row.AddCell()
  64. fill := NewFill("solid", "00FF0000", "FF000000")
  65. style := NewStyle()
  66. style.Fill = *fill
  67. cell.SetStyle(style)
  68. style = cell.GetStyle()
  69. _, xFill, _, _ := style.makeXLSXStyleElements()
  70. xPatternFill := xFill.PatternFill
  71. c.Assert(xPatternFill.PatternType, Equals, "solid")
  72. c.Assert(xPatternFill.FgColor.RGB, Equals, "00FF0000")
  73. c.Assert(xPatternFill.BgColor.RGB, Equals, "FF000000")
  74. }
  75. // Test that GetStyle correctly converts the xlsxStyle.Borders.
  76. func (s *CellSuite) TestGetStyleWithBorders(c *C) {
  77. border := *NewBorder("thin", "thin", "thin", "thin")
  78. style := NewStyle()
  79. style.Border = border
  80. cell := Cell{Value: "123", style: style}
  81. style = cell.GetStyle()
  82. _, _, xBorder, _ := style.makeXLSXStyleElements()
  83. c.Assert(xBorder.Left.Style, Equals, "thin")
  84. c.Assert(xBorder.Right.Style, Equals, "thin")
  85. c.Assert(xBorder.Top.Style, Equals, "thin")
  86. c.Assert(xBorder.Bottom.Style, Equals, "thin")
  87. }
  88. // We can return a string representation of the formatted data
  89. func (l *CellSuite) TestSetFloatWithFormat(c *C) {
  90. cell := Cell{}
  91. cell.SetFloatWithFormat(37947.75334343, "yyyy/mm/dd")
  92. c.Assert(cell.Value, Equals, "37947.75334343")
  93. c.Assert(cell.NumFmt, Equals, "yyyy/mm/dd")
  94. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  95. }
  96. func (l *CellSuite) TestSetFloat(c *C) {
  97. cell := Cell{}
  98. cell.SetFloat(0)
  99. c.Assert(cell.Value, Equals, "0")
  100. cell.SetFloat(0.000005)
  101. c.Assert(cell.Value, Equals, "0.000005")
  102. cell.SetFloat(100.0)
  103. c.Assert(cell.Value, Equals, "100")
  104. cell.SetFloat(37947.75334343)
  105. c.Assert(cell.Value, Equals, "37947.75334343")
  106. }
  107. func (l *CellSuite) TestGeneralNumberHandling(c *C) {
  108. // If you go to Excel, make a new file, type 18.99 in a cell, and save, what you will get is a
  109. // cell where the format is General and the storage type is Number, that contains the value 18.989999999999998.
  110. // The correct way to format this should be 18.99.
  111. // 1.1 will get you the same, with a stored value of 1.1000000000000001.
  112. // Also, numbers greater than 1e11 and less than 1e-9 wil be shown as scientific notation.
  113. testCases := []struct {
  114. value string
  115. formattedValueOutput string
  116. noScientificValueOutput string
  117. }{
  118. {
  119. value: "18.989999999999998",
  120. formattedValueOutput: "18.99",
  121. noScientificValueOutput: "18.99",
  122. },
  123. {
  124. value: "1.1000000000000001",
  125. formattedValueOutput: "1.1",
  126. noScientificValueOutput: "1.1",
  127. },
  128. {
  129. value: "0.0000000000000001",
  130. formattedValueOutput: "1E-16",
  131. noScientificValueOutput: "0.0000000000000001",
  132. },
  133. {
  134. value: "0.000000000000008",
  135. formattedValueOutput: "8E-15",
  136. noScientificValueOutput: "0.000000000000008",
  137. },
  138. {
  139. value: "1000000000000000000",
  140. formattedValueOutput: "1E+18",
  141. noScientificValueOutput: "1000000000000000000",
  142. },
  143. {
  144. value: "1230000000000000000",
  145. formattedValueOutput: "1.23E+18",
  146. noScientificValueOutput: "1230000000000000000",
  147. },
  148. {
  149. value: "12345678",
  150. formattedValueOutput: "12345678",
  151. noScientificValueOutput: "12345678",
  152. },
  153. {
  154. value: "0",
  155. formattedValueOutput: "0",
  156. noScientificValueOutput: "0",
  157. },
  158. {
  159. value: "-18.989999999999998",
  160. formattedValueOutput: "-18.99",
  161. noScientificValueOutput: "-18.99",
  162. },
  163. {
  164. value: "-1.1000000000000001",
  165. formattedValueOutput: "-1.1",
  166. noScientificValueOutput: "-1.1",
  167. },
  168. {
  169. value: "-0.0000000000000001",
  170. formattedValueOutput: "-1E-16",
  171. noScientificValueOutput: "-0.0000000000000001",
  172. },
  173. {
  174. value: "-0.000000000000008",
  175. formattedValueOutput: "-8E-15",
  176. noScientificValueOutput: "-0.000000000000008",
  177. },
  178. {
  179. value: "-1000000000000000000",
  180. formattedValueOutput: "-1E+18",
  181. noScientificValueOutput: "-1000000000000000000",
  182. },
  183. {
  184. value: "-1230000000000000000",
  185. formattedValueOutput: "-1.23E+18",
  186. noScientificValueOutput: "-1230000000000000000",
  187. },
  188. {
  189. value: "-12345678",
  190. formattedValueOutput: "-12345678",
  191. noScientificValueOutput: "-12345678",
  192. },
  193. }
  194. for _, testCase := range testCases {
  195. cell := Cell{
  196. cellType: CellTypeNumeric,
  197. NumFmt: builtInNumFmt[builtInNumFmtIndex_GENERAL],
  198. Value: testCase.value,
  199. }
  200. val, err := cell.FormattedValue()
  201. if err != nil {
  202. c.Fatal(err)
  203. }
  204. c.Assert(val, Equals, testCase.formattedValueOutput)
  205. val, err = cell.GeneralNumericWithoutScientific()
  206. if err != nil {
  207. c.Fatal(err)
  208. }
  209. c.Assert(val, Equals, testCase.noScientificValueOutput)
  210. }
  211. }
  212. // TestCellTypeFormatHandling tests all cell types other than numeric. Numeric cells are tested above since those
  213. // cells have so many edge cases.
  214. func (l *CellSuite) TestCellTypeFormatHandling(c *C) {
  215. testCases := []struct {
  216. cellType CellType
  217. numFmt string
  218. value string
  219. formattedValueOutput string
  220. expectError bool
  221. }{
  222. // All of the string cell types, will return only the string format if there is no @ symbol in the format.
  223. {
  224. cellType: CellTypeInline,
  225. numFmt: `0;0;0;"Error"`,
  226. value: "asdf",
  227. formattedValueOutput: "Error",
  228. },
  229. {
  230. cellType: CellTypeString,
  231. numFmt: `0;0;0;"Error"`,
  232. value: "asdf",
  233. formattedValueOutput: "Error",
  234. },
  235. {
  236. cellType: CellTypeStringFormula,
  237. numFmt: `0;0;0;"Error"`,
  238. value: "asdf",
  239. formattedValueOutput: "Error",
  240. },
  241. // Errors are returned as is regardless of what the format shows
  242. {
  243. cellType: CellTypeError,
  244. numFmt: `0;0;0;"Error"`,
  245. value: "#NAME?",
  246. formattedValueOutput: "#NAME?",
  247. },
  248. {
  249. cellType: CellTypeError,
  250. numFmt: `"$"@`,
  251. value: "#######",
  252. formattedValueOutput: "#######",
  253. },
  254. // Dates are returned as is regardless of what the format shows
  255. {
  256. cellType: CellTypeDate,
  257. numFmt: `"$"@`,
  258. value: "2017-10-24T15:29:30+00:00",
  259. formattedValueOutput: "2017-10-24T15:29:30+00:00",
  260. },
  261. // Make sure the format used above would have done something for a string
  262. {
  263. cellType: CellTypeString,
  264. numFmt: `"$"@`,
  265. value: "#######",
  266. formattedValueOutput: "$#######",
  267. },
  268. // For bool cells, 0 is false, 1 is true, anything else will error
  269. {
  270. cellType: CellTypeBool,
  271. numFmt: `"$"@`,
  272. value: "1",
  273. formattedValueOutput: "TRUE",
  274. },
  275. {
  276. cellType: CellTypeBool,
  277. numFmt: `"$"@`,
  278. value: "0",
  279. formattedValueOutput: "FALSE",
  280. },
  281. {
  282. cellType: CellTypeBool,
  283. numFmt: `"$"@`,
  284. value: "2",
  285. expectError: true,
  286. formattedValueOutput: "2",
  287. },
  288. {
  289. cellType: CellTypeBool,
  290. numFmt: `"$"@`,
  291. value: "2",
  292. expectError: true,
  293. formattedValueOutput: "2",
  294. },
  295. // Invalid cell type should cause an error
  296. {
  297. cellType: CellType(7),
  298. numFmt: `0`,
  299. value: "1.0",
  300. expectError: true,
  301. formattedValueOutput: "1.0",
  302. },
  303. }
  304. for _, testCase := range testCases {
  305. cell := Cell{
  306. cellType: testCase.cellType,
  307. NumFmt: testCase.numFmt,
  308. Value: testCase.value,
  309. }
  310. val, err := cell.FormattedValue()
  311. if err != nil != testCase.expectError {
  312. c.Fatal(err)
  313. }
  314. c.Assert(val, Equals, testCase.formattedValueOutput)
  315. }
  316. }
  317. func (s *CellSuite) TestIsTime(c *C) {
  318. cell := Cell{}
  319. isTime := cell.IsTime()
  320. c.Assert(isTime, Equals, false)
  321. cell.Value = "43221"
  322. c.Assert(isTime, Equals, false)
  323. cell.NumFmt = "d-mmm-yy"
  324. cell.Value = "43221"
  325. isTime = cell.IsTime()
  326. c.Assert(isTime, Equals, true)
  327. }
  328. func (s *CellSuite) TestGetTime(c *C) {
  329. cell := Cell{}
  330. cell.SetFloat(0)
  331. date, err := cell.GetTime(false)
  332. c.Assert(err, Equals, nil)
  333. c.Assert(date, Equals, time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC))
  334. cell.SetFloat(39813.0)
  335. date, err = cell.GetTime(true)
  336. c.Assert(err, Equals, nil)
  337. c.Assert(date, Equals, time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC))
  338. cell.Value = "d"
  339. _, err = cell.GetTime(false)
  340. c.Assert(err, NotNil)
  341. }
  342. // FormattedValue returns an error for formatting errors
  343. func (l *CellSuite) TestFormattedValueErrorsOnBadFormat(c *C) {
  344. cell := Cell{Value: "Fudge Cake", cellType: CellTypeNumeric}
  345. cell.NumFmt = "#,##0 ;(#,##0)"
  346. value, err := cell.FormattedValue()
  347. c.Assert(value, Equals, "Fudge Cake")
  348. c.Assert(err, NotNil)
  349. c.Assert(err.Error(), Equals, "strconv.ParseFloat: parsing \"Fudge Cake\": invalid syntax")
  350. }
  351. // formattedValueChecker removes all the boilerplate for testing Cell.FormattedValue
  352. // after its change from returning one value (a string) to two values (string, error)
  353. // This allows all the old one-line asserts in the test to continue to be one
  354. // line, instead of multi-line with error checking.
  355. type formattedValueChecker struct {
  356. c *C
  357. }
  358. func (fvc *formattedValueChecker) Equals(cell Cell, expected string) {
  359. val, err := cell.FormattedValue()
  360. if err != nil {
  361. fvc.c.Error(err)
  362. }
  363. fvc.c.Assert(val, Equals, expected)
  364. }
  365. func cellsFormattedValueEquals(t *testing.T, cell *Cell, expected string) {
  366. val, err := cell.FormattedValue()
  367. if err != nil {
  368. t.Error(err)
  369. }
  370. if val != expected {
  371. t.Errorf("Expected cell.FormattedValue() to be %v, got %v", expected, val)
  372. }
  373. }
  374. // We can return a string representation of the formatted data
  375. func (l *CellSuite) TestFormattedValue(c *C) {
  376. cell := Cell{Value: "37947.7500001", cellType: CellTypeNumeric}
  377. negativeCell := Cell{Value: "-37947.7500001", cellType: CellTypeNumeric}
  378. smallCell := Cell{Value: "0.007", cellType: CellTypeNumeric}
  379. earlyCell := Cell{Value: "2.1", cellType: CellTypeNumeric}
  380. fvc := formattedValueChecker{c: c}
  381. cell.NumFmt = "general"
  382. fvc.Equals(cell, "37947.7500001")
  383. negativeCell.NumFmt = "general"
  384. fvc.Equals(negativeCell, "-37947.7500001")
  385. // TODO: This test is currently broken. For a string type cell, I
  386. // don't think FormattedValue() should be doing a numeric conversion on the value
  387. // before returning the string.
  388. cell.NumFmt = "0"
  389. fvc.Equals(cell, "37948")
  390. cell.NumFmt = "#,##0" // For the time being we're not doing
  391. // this comma formatting, so it'll fall back to the related
  392. // non-comma form.
  393. fvc.Equals(cell, "37948")
  394. cell.NumFmt = "#,##0.00;(#,##0.00)"
  395. fvc.Equals(cell, "37947.75")
  396. cell.NumFmt = "0.00"
  397. fvc.Equals(cell, "37947.75")
  398. cell.NumFmt = "#,##0.00" // For the time being we're not doing
  399. // this comma formatting, so it'll fall back to the related
  400. // non-comma form.
  401. fvc.Equals(cell, "37947.75")
  402. cell.NumFmt = "#,##0 ;(#,##0)"
  403. fvc.Equals(cell, "37948")
  404. negativeCell.NumFmt = "#,##0 ;(#,##0)"
  405. fvc.Equals(negativeCell, "(37948)")
  406. cell.NumFmt = "#,##0 ;[red](#,##0)"
  407. fvc.Equals(cell, "37948")
  408. negativeCell.NumFmt = "#,##0 ;[red](#,##0)"
  409. fvc.Equals(negativeCell, "(37948)")
  410. negativeCell.NumFmt = "#,##0.00;(#,##0.00)"
  411. fvc.Equals(negativeCell, "(37947.75)")
  412. cell.NumFmt = "0%"
  413. fvc.Equals(cell, "3794775%")
  414. cell.NumFmt = "0.00%"
  415. fvc.Equals(cell, "3794775.00%")
  416. cell.NumFmt = "0.00e+00"
  417. fvc.Equals(cell, "3.794775e+04")
  418. cell.NumFmt = "##0.0e+0" // This is wrong, but we'll use it for now.
  419. fvc.Equals(cell, "3.794775e+04")
  420. cell.NumFmt = "mm-dd-yy"
  421. fvc.Equals(cell, "11-22-03")
  422. cell.NumFmt = "d-mmm-yy"
  423. fvc.Equals(cell, "22-Nov-03")
  424. earlyCell.NumFmt = "d-mmm-yy"
  425. fvc.Equals(earlyCell, "1-Jan-00")
  426. cell.NumFmt = "d-mmm"
  427. fvc.Equals(cell, "22-Nov")
  428. earlyCell.NumFmt = "d-mmm"
  429. fvc.Equals(earlyCell, "1-Jan")
  430. cell.NumFmt = "mmm-yy"
  431. fvc.Equals(cell, "Nov-03")
  432. cell.NumFmt = "h:mm am/pm"
  433. fvc.Equals(cell, "6:00 pm")
  434. smallCell.NumFmt = "h:mm am/pm"
  435. fvc.Equals(smallCell, "12:10 am")
  436. cell.NumFmt = "h:mm:ss am/pm"
  437. fvc.Equals(cell, "6:00:00 pm")
  438. cell.NumFmt = "hh:mm:ss"
  439. fvc.Equals(cell, "18:00:00")
  440. smallCell.NumFmt = "h:mm:ss am/pm"
  441. fvc.Equals(smallCell, "12:10:04 am")
  442. cell.NumFmt = "h:mm"
  443. fvc.Equals(cell, "18:00")
  444. smallCell.NumFmt = "h:mm"
  445. fvc.Equals(smallCell, "00:10")
  446. smallCell.NumFmt = "hh:mm"
  447. fvc.Equals(smallCell, "00:10")
  448. cell.NumFmt = "h:mm:ss"
  449. fvc.Equals(cell, "18:00:00")
  450. cell.NumFmt = "hh:mm:ss"
  451. fvc.Equals(cell, "18:00:00")
  452. smallCell.NumFmt = "hh:mm:ss"
  453. fvc.Equals(smallCell, "00:10:04")
  454. smallCell.NumFmt = "h:mm:ss"
  455. fvc.Equals(smallCell, "00:10:04")
  456. cell.NumFmt = "m/d/yy h:mm"
  457. fvc.Equals(cell, "11/22/03 18:00")
  458. cell.NumFmt = "m/d/yy hh:mm"
  459. fvc.Equals(cell, "11/22/03 18:00")
  460. smallCell.NumFmt = "m/d/yy h:mm"
  461. fvc.Equals(smallCell, "12/30/99 00:10")
  462. smallCell.NumFmt = "m/d/yy hh:mm"
  463. fvc.Equals(smallCell, "12/30/99 00:10")
  464. earlyCell.NumFmt = "m/d/yy hh:mm"
  465. fvc.Equals(earlyCell, "1/1/00 02:24")
  466. earlyCell.NumFmt = "m/d/yy h:mm"
  467. fvc.Equals(earlyCell, "1/1/00 02:24")
  468. cell.NumFmt = "mm:ss"
  469. fvc.Equals(cell, "00:00")
  470. smallCell.NumFmt = "mm:ss"
  471. fvc.Equals(smallCell, "10:04")
  472. cell.NumFmt = "[hh]:mm:ss"
  473. fvc.Equals(cell, "18:00:00")
  474. cell.NumFmt = "[h]:mm:ss"
  475. fvc.Equals(cell, "18:00:00")
  476. smallCell.NumFmt = "[h]:mm:ss"
  477. fvc.Equals(smallCell, "10:04")
  478. const (
  479. expect1 = "0000.0086"
  480. expect2 = "1004.8000"
  481. format = "mmss.0000"
  482. tlen = len(format)
  483. )
  484. for i := 0; i < 3; i++ {
  485. tfmt := format[0 : tlen-i]
  486. cell.NumFmt = tfmt
  487. fvc.Equals(cell, expect1[0:tlen-i])
  488. smallCell.NumFmt = tfmt
  489. fvc.Equals(smallCell, expect2[0:tlen-i])
  490. }
  491. cell.NumFmt = "yyyy\\-mm\\-dd"
  492. fvc.Equals(cell, "2003\\-11\\-22")
  493. cell.NumFmt = "dd/mm/yyyy hh:mm:ss"
  494. fvc.Equals(cell, "22/11/2003 18:00:00")
  495. cell.NumFmt = "dd/mm/yy"
  496. fvc.Equals(cell, "22/11/03")
  497. earlyCell.NumFmt = "dd/mm/yy"
  498. fvc.Equals(earlyCell, "01/01/00")
  499. cell.NumFmt = "hh:mm:ss"
  500. fvc.Equals(cell, "18:00:00")
  501. smallCell.NumFmt = "hh:mm:ss"
  502. fvc.Equals(smallCell, "00:10:04")
  503. cell.NumFmt = "dd/mm/yy\\ hh:mm"
  504. fvc.Equals(cell, "22/11/03\\ 18:00")
  505. cell.NumFmt = "yyyy/mm/dd"
  506. fvc.Equals(cell, "2003/11/22")
  507. cell.NumFmt = "yy-mm-dd"
  508. fvc.Equals(cell, "03-11-22")
  509. cell.NumFmt = "d-mmm-yyyy"
  510. fvc.Equals(cell, "22-Nov-2003")
  511. earlyCell.NumFmt = "d-mmm-yyyy"
  512. fvc.Equals(earlyCell, "1-Jan-1900")
  513. cell.NumFmt = "m/d/yy"
  514. fvc.Equals(cell, "11/22/03")
  515. earlyCell.NumFmt = "m/d/yy"
  516. fvc.Equals(earlyCell, "1/1/00")
  517. cell.NumFmt = "m/d/yyyy"
  518. fvc.Equals(cell, "11/22/2003")
  519. earlyCell.NumFmt = "m/d/yyyy"
  520. fvc.Equals(earlyCell, "1/1/1900")
  521. cell.NumFmt = "dd-mmm-yyyy"
  522. fvc.Equals(cell, "22-Nov-2003")
  523. cell.NumFmt = "dd/mm/yyyy"
  524. fvc.Equals(cell, "22/11/2003")
  525. cell.NumFmt = "mm/dd/yy hh:mm am/pm"
  526. fvc.Equals(cell, "11/22/03 06:00 pm")
  527. cell.NumFmt = "mm/dd/yy h:mm am/pm"
  528. fvc.Equals(cell, "11/22/03 6:00 pm")
  529. cell.NumFmt = "mm/dd/yyyy hh:mm:ss"
  530. fvc.Equals(cell, "11/22/2003 18:00:00")
  531. smallCell.NumFmt = "mm/dd/yyyy hh:mm:ss"
  532. fvc.Equals(smallCell, "12/30/1899 00:10:04")
  533. cell.NumFmt = "yyyy-mm-dd hh:mm:ss"
  534. fvc.Equals(cell, "2003-11-22 18:00:00")
  535. smallCell.NumFmt = "yyyy-mm-dd hh:mm:ss"
  536. fvc.Equals(smallCell, "1899-12-30 00:10:04")
  537. cell.NumFmt = "mmmm d, yyyy"
  538. fvc.Equals(cell, "November 22, 2003")
  539. smallCell.NumFmt = "mmmm d, yyyy"
  540. fvc.Equals(smallCell, "December 30, 1899")
  541. cell.NumFmt = "dddd, mmmm dd, yyyy"
  542. fvc.Equals(cell, "Saturday, November 22, 2003")
  543. smallCell.NumFmt = "dddd, mmmm dd, yyyy"
  544. fvc.Equals(smallCell, "Saturday, December 30, 1899")
  545. }
  546. func (s *CellSuite) TestTimeToExcelTime(c *C) {
  547. c.Assert(0.0, Equals, TimeToExcelTime(time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC), false))
  548. c.Assert(-1462.0, Equals, TimeToExcelTime(time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC), true))
  549. c.Assert(25569.0, Equals, TimeToExcelTime(time.Unix(0, 0), false))
  550. c.Assert(43269.0, Equals, TimeToExcelTime(time.Date(2018, 6, 18, 0, 0, 0, 0, time.UTC), false))
  551. c.Assert(401769.0, Equals, TimeToExcelTime(time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC), false))
  552. smallDate := time.Date(1899, 12, 30, 0, 0, 0, 1000, time.UTC)
  553. smallExcelTime := TimeToExcelTime(smallDate, false)
  554. c.Assert(true, Equals, 0.0 != smallExcelTime)
  555. roundTrippedDate := TimeFromExcelTime(smallExcelTime, false)
  556. c.Assert(roundTrippedDate, Equals, smallDate)
  557. }
  558. // test setters and getters
  559. func (s *CellSuite) TestSetterGetters(c *C) {
  560. cell := Cell{}
  561. cell.SetString("hello world")
  562. if val, err := cell.FormattedValue(); err != nil {
  563. c.Error(err)
  564. } else {
  565. c.Assert(val, Equals, "hello world")
  566. }
  567. c.Assert(cell.Type(), Equals, CellTypeString)
  568. cell.SetInt(1024)
  569. intValue, _ := cell.Int()
  570. c.Assert(intValue, Equals, 1024)
  571. c.Assert(cell.NumFmt, Equals, builtInNumFmt[builtInNumFmtIndex_GENERAL])
  572. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  573. cell.SetInt64(1024)
  574. int64Value, _ := cell.Int64()
  575. c.Assert(int64Value, Equals, int64(1024))
  576. c.Assert(cell.NumFmt, Equals, builtInNumFmt[builtInNumFmtIndex_GENERAL])
  577. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  578. cell.SetFloat(1.024)
  579. float, _ := cell.Float()
  580. intValue, _ = cell.Int() // convert
  581. c.Assert(float, Equals, 1.024)
  582. c.Assert(intValue, Equals, 1)
  583. c.Assert(cell.NumFmt, Equals, builtInNumFmt[builtInNumFmtIndex_GENERAL])
  584. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  585. cell.SetFormula("10+20")
  586. c.Assert(cell.Formula(), Equals, "10+20")
  587. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  588. cell.SetStringFormula("A1")
  589. c.Assert(cell.Formula(), Equals, "A1")
  590. c.Assert(cell.Type(), Equals, CellTypeStringFormula)
  591. }
  592. // TestOddInput is a regression test for #101. When the number format
  593. // was "@" (string), the input below caused a crash in strconv.ParseFloat.
  594. // The solution was to check if cell.Value was both a CellTypeString and
  595. // had a NumFmt of "general" or "@" and short-circuit FormattedValue() if so.
  596. func (s *CellSuite) TestOddInput(c *C) {
  597. cell := Cell{}
  598. odd := `[1],[12,"DATE NOT NULL DEFAULT '0000-00-00'"]`
  599. cell.Value = odd
  600. cell.NumFmt = "@"
  601. if val, err := cell.FormattedValue(); err != nil {
  602. c.Error(err)
  603. } else {
  604. c.Assert(val, Equals, odd)
  605. }
  606. }
  607. // TestBool tests basic Bool getting and setting booleans.
  608. func (s *CellSuite) TestBool(c *C) {
  609. cell := Cell{}
  610. cell.SetBool(true)
  611. c.Assert(cell.Value, Equals, "1")
  612. c.Assert(cell.Bool(), Equals, true)
  613. cell.SetBool(false)
  614. c.Assert(cell.Value, Equals, "0")
  615. c.Assert(cell.Bool(), Equals, false)
  616. }
  617. // TestStringBool tests calling Bool on a non CellTypeBool value.
  618. func (s *CellSuite) TestStringBool(c *C) {
  619. cell := Cell{}
  620. cell.SetInt(0)
  621. c.Assert(cell.Bool(), Equals, false)
  622. cell.SetInt(1)
  623. c.Assert(cell.Bool(), Equals, true)
  624. cell.SetString("")
  625. c.Assert(cell.Bool(), Equals, false)
  626. cell.SetString("0")
  627. c.Assert(cell.Bool(), Equals, true)
  628. }
  629. // TestSetValue tests whether SetValue handle properly for different type values.
  630. func (s *CellSuite) TestSetValue(c *C) {
  631. cell := Cell{}
  632. // int
  633. for _, i := range []interface{}{1, int8(1), int16(1), int32(1), int64(1)} {
  634. cell.SetValue(i)
  635. val, err := cell.Int64()
  636. c.Assert(err, IsNil)
  637. c.Assert(val, Equals, int64(1))
  638. }
  639. // float
  640. for _, i := range []interface{}{1.11, float32(1.11), float64(1.11)} {
  641. cell.SetValue(i)
  642. val, err := cell.Float()
  643. c.Assert(err, IsNil)
  644. c.Assert(val, Equals, 1.11)
  645. }
  646. // In the naive implementation using go fmt "%v", this test would fail and the cell.Value would be "1e-06"
  647. for _, i := range []interface{}{0.000001, float32(0.000001), float64(0.000001)} {
  648. cell.SetValue(i)
  649. c.Assert(cell.Value, Equals, "0.000001")
  650. val, err := cell.Float()
  651. c.Assert(err, IsNil)
  652. c.Assert(val, Equals, 0.000001)
  653. }
  654. // time
  655. cell.SetValue(time.Unix(0, 0))
  656. val, err := cell.Float()
  657. c.Assert(err, IsNil)
  658. c.Assert(math.Floor(val), Equals, 25569.0)
  659. // string and nil
  660. for _, i := range []interface{}{nil, "", []byte("")} {
  661. cell.SetValue(i)
  662. c.Assert(cell.Value, Equals, "")
  663. }
  664. // others
  665. cell.SetValue([]string{"test"})
  666. c.Assert(cell.Value, Equals, "[test]")
  667. }
  668. func (s *CellSuite) TestSetDateWithOptions(c *C) {
  669. cell := Cell{}
  670. // time
  671. cell.SetDate(time.Unix(0, 0))
  672. val, err := cell.Float()
  673. c.Assert(err, IsNil)
  674. c.Assert(math.Floor(val), Equals, 25569.0)
  675. // our test subject
  676. date2016UTC := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
  677. // test ny timezone
  678. nyTZ, err := time.LoadLocation("America/New_York")
  679. c.Assert(err, IsNil)
  680. cell.SetDateWithOptions(date2016UTC, DateTimeOptions{
  681. ExcelTimeFormat: "test_format1",
  682. Location: nyTZ,
  683. })
  684. val, err = cell.Float()
  685. c.Assert(err, IsNil)
  686. c.Assert(val, Equals, TimeToExcelTime(time.Date(2016, 1, 1, 7, 0, 0, 0, time.UTC), false))
  687. // test jp timezone
  688. jpTZ, err := time.LoadLocation("Asia/Tokyo")
  689. c.Assert(err, IsNil)
  690. cell.SetDateWithOptions(date2016UTC, DateTimeOptions{
  691. ExcelTimeFormat: "test_format2",
  692. Location: jpTZ,
  693. })
  694. val, err = cell.Float()
  695. c.Assert(err, IsNil)
  696. c.Assert(val, Equals, TimeToExcelTime(time.Date(2016, 1, 1, 21, 0, 0, 0, time.UTC), false))
  697. }
  698. func (s *CellSuite) TestIsTimeFormat(c *C) {
  699. c.Assert(isTimeFormat("yy"), Equals, true)
  700. c.Assert(isTimeFormat("hh"), Equals, true)
  701. c.Assert(isTimeFormat("h"), Equals, true)
  702. c.Assert(isTimeFormat("am/pm"), Equals, true)
  703. c.Assert(isTimeFormat("AM/PM"), Equals, true)
  704. c.Assert(isTimeFormat("A/P"), Equals, true)
  705. c.Assert(isTimeFormat("a/p"), Equals, true)
  706. c.Assert(isTimeFormat("ss"), Equals, true)
  707. c.Assert(isTimeFormat("mm"), Equals, true)
  708. c.Assert(isTimeFormat(":"), Equals, false)
  709. c.Assert(isTimeFormat("z"), Equals, false)
  710. }
  711. func (s *CellSuite) TestIs12HourtTime(c *C) {
  712. c.Assert(is12HourTime("am/pm"), Equals, true)
  713. c.Assert(is12HourTime("AM/PM"), Equals, true)
  714. c.Assert(is12HourTime("a/p"), Equals, true)
  715. c.Assert(is12HourTime("A/P"), Equals, true)
  716. c.Assert(is12HourTime("x"), Equals, false)
  717. }
  718. func (s *CellSuite) TestFallbackTo(c *C) {
  719. testCases := []struct {
  720. cellType *CellType
  721. cellData string
  722. fallback CellType
  723. expectedReturn CellType
  724. }{
  725. {
  726. cellType: CellTypeNumeric.Ptr(),
  727. cellData: `string`,
  728. fallback: CellTypeString,
  729. expectedReturn: CellTypeString,
  730. },
  731. {
  732. cellType: nil,
  733. cellData: `string`,
  734. fallback: CellTypeNumeric,
  735. expectedReturn: CellTypeNumeric,
  736. },
  737. {
  738. cellType: CellTypeNumeric.Ptr(),
  739. cellData: `300.24`,
  740. fallback: CellTypeString,
  741. expectedReturn: CellTypeNumeric,
  742. },
  743. {
  744. cellType: CellTypeNumeric.Ptr(),
  745. cellData: `300`,
  746. fallback: CellTypeString,
  747. expectedReturn: CellTypeNumeric,
  748. },
  749. }
  750. for _, testCase := range testCases {
  751. c.Assert(testCase.cellType.fallbackTo(testCase.cellData, testCase.fallback), Equals, testCase.expectedReturn)
  752. }
  753. }