cell_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. package xlsx
  2. import (
  3. . "gopkg.in/check.v1"
  4. )
  5. type CellSuite struct{}
  6. var _ = Suite(&CellSuite{})
  7. // Test that we can set and get a Value from a Cell
  8. func (s *CellSuite) TestValueSet(c *C) {
  9. // Note, this test is fairly pointless, it serves mostly to
  10. // reinforce that this functionality is important, and should
  11. // the mechanics of this all change at some point, to remind
  12. // us not to lose this.
  13. cell := Cell{}
  14. cell.Value = "A string"
  15. c.Assert(cell.Value, Equals, "A string")
  16. }
  17. // Test that GetStyle correctly converts the xlsxStyle.Fonts.
  18. func (s *CellSuite) TestGetStyleWithFonts(c *C) {
  19. font := NewFont(10, "Calibra")
  20. style := NewStyle()
  21. style.Font = *font
  22. cell := &Cell{Value: "123", style: style}
  23. style = cell.GetStyle()
  24. c.Assert(style, NotNil)
  25. c.Assert(style.Font.Size, Equals, 10)
  26. c.Assert(style.Font.Name, Equals, "Calibra")
  27. }
  28. // Test that SetStyle correctly translates into a xlsxFont element
  29. func (s *CellSuite) TestSetStyleWithFonts(c *C) {
  30. file := NewFile()
  31. sheet, _ := file.AddSheet("Test")
  32. row := sheet.AddRow()
  33. cell := row.AddCell()
  34. font := NewFont(12, "Calibra")
  35. style := NewStyle()
  36. style.Font = *font
  37. cell.SetStyle(style)
  38. style = cell.GetStyle()
  39. xFont, _, _, _ := style.makeXLSXStyleElements()
  40. c.Assert(xFont.Sz.Val, Equals, "12")
  41. c.Assert(xFont.Name.Val, Equals, "Calibra")
  42. }
  43. // Test that GetStyle correctly converts the xlsxStyle.Fills.
  44. func (s *CellSuite) TestGetStyleWithFills(c *C) {
  45. fill := *NewFill("solid", "FF000000", "00FF0000")
  46. style := NewStyle()
  47. style.Fill = fill
  48. cell := &Cell{Value: "123", style: style}
  49. style = cell.GetStyle()
  50. _, xFill, _, _ := style.makeXLSXStyleElements()
  51. c.Assert(xFill.PatternFill.PatternType, Equals, "solid")
  52. c.Assert(xFill.PatternFill.BgColor.RGB, Equals, "00FF0000")
  53. c.Assert(xFill.PatternFill.FgColor.RGB, Equals, "FF000000")
  54. }
  55. // Test that SetStyle correctly updates xlsxStyle.Fills.
  56. func (s *CellSuite) TestSetStyleWithFills(c *C) {
  57. file := NewFile()
  58. sheet, _ := file.AddSheet("Test")
  59. row := sheet.AddRow()
  60. cell := row.AddCell()
  61. fill := NewFill("solid", "00FF0000", "FF000000")
  62. style := NewStyle()
  63. style.Fill = *fill
  64. cell.SetStyle(style)
  65. style = cell.GetStyle()
  66. _, xFill, _, _ := style.makeXLSXStyleElements()
  67. xPatternFill := xFill.PatternFill
  68. c.Assert(xPatternFill.PatternType, Equals, "solid")
  69. c.Assert(xPatternFill.FgColor.RGB, Equals, "00FF0000")
  70. c.Assert(xPatternFill.BgColor.RGB, Equals, "FF000000")
  71. }
  72. // Test that GetStyle correctly converts the xlsxStyle.Borders.
  73. func (s *CellSuite) TestGetStyleWithBorders(c *C) {
  74. border := *NewBorder("thin", "thin", "thin", "thin")
  75. style := NewStyle()
  76. style.Border = border
  77. cell := Cell{Value: "123", style: style}
  78. style = cell.GetStyle()
  79. _, _, xBorder, _ := style.makeXLSXStyleElements()
  80. c.Assert(xBorder.Left.Style, Equals, "thin")
  81. c.Assert(xBorder.Right.Style, Equals, "thin")
  82. c.Assert(xBorder.Top.Style, Equals, "thin")
  83. c.Assert(xBorder.Bottom.Style, Equals, "thin")
  84. }
  85. // We can return a string representation of the formatted data
  86. func (l *CellSuite) TestSetFloatWithFormat(c *C) {
  87. cell := Cell{}
  88. cell.SetFloatWithFormat(37947.75334343, "yyyy/mm/dd")
  89. c.Assert(cell.Value, Equals, "37947.75334343")
  90. c.Assert(cell.NumFmt, Equals, "yyyy/mm/dd")
  91. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  92. }
  93. func (l *CellSuite) TestSetFloat(c *C) {
  94. cell := Cell{}
  95. cell.SetFloat(0)
  96. c.Assert(cell.Value, Equals, "0")
  97. cell.SetFloat(0.000005)
  98. c.Assert(cell.Value, Equals, "5e-06")
  99. cell.SetFloat(100.0)
  100. c.Assert(cell.Value, Equals, "100")
  101. cell.SetFloat(37947.75334343)
  102. c.Assert(cell.Value, Equals, "37947.75334343")
  103. }
  104. // FormattedValue returns an error for formatting errors
  105. func (l *CellSuite) TestFormattedValueErrorsOnBadFormat(c *C) {
  106. cell := Cell{Value: "Fudge Cake"}
  107. cell.NumFmt = "#,##0 ;(#,##0)"
  108. value, err := cell.FormattedValue()
  109. c.Assert(value, Equals, "Fudge Cake")
  110. c.Assert(err, NotNil)
  111. c.Assert(err.Error(), Equals, "strconv.ParseFloat: parsing \"Fudge Cake\": invalid syntax")
  112. }
  113. // FormattedValue returns a string containing error text for formatting errors
  114. func (l *CellSuite) TestFormattedValueReturnsErrorAsValueForBadFormat(c *C) {
  115. cell := Cell{Value: "Fudge Cake"}
  116. cell.NumFmt = "#,##0 ;(#,##0)"
  117. _, err := cell.FormattedValue()
  118. c.Assert(err.Error(), Equals, "strconv.ParseFloat: parsing \"Fudge Cake\": invalid syntax")
  119. }
  120. // formattedValueChecker removes all the boilerplate for testing Cell.FormattedValue
  121. // after its change from returning one value (a string) to two values (string, error)
  122. // This allows all the old one-line asserts in the test to continue to be one
  123. // line, instead of multi-line with error checking.
  124. type formattedValueChecker struct {
  125. c *C
  126. }
  127. func (fvc *formattedValueChecker) Equals(cell Cell, expected string) {
  128. val, err := cell.FormattedValue()
  129. if err != nil {
  130. fvc.c.Error(err)
  131. }
  132. fvc.c.Assert(val, Equals, expected)
  133. }
  134. // We can return a string representation of the formatted data
  135. func (l *CellSuite) TestFormattedValue(c *C) {
  136. // XXX TODO, this test should probably be split down, and made
  137. // in terms of SafeFormattedValue, as FormattedValue wraps
  138. // that function now.
  139. cell := Cell{Value: "37947.7500001"}
  140. negativeCell := Cell{Value: "-37947.7500001"}
  141. smallCell := Cell{Value: "0.007"}
  142. earlyCell := Cell{Value: "2.1"}
  143. fvc := formattedValueChecker{c: c}
  144. cell.NumFmt = "general"
  145. fvc.Equals(cell, "37947.7500001")
  146. negativeCell.NumFmt = "general"
  147. fvc.Equals(negativeCell, "-37947.7500001")
  148. // TODO: This test is currently broken. For a string type cell, I
  149. // don't think FormattedValue() should be doing a numeric conversion on the value
  150. // before returning the string.
  151. cell.NumFmt = "0"
  152. fvc.Equals(cell, "37947")
  153. cell.NumFmt = "#,##0" // For the time being we're not doing
  154. // this comma formatting, so it'll fall back to the related
  155. // non-comma form.
  156. fvc.Equals(cell, "37947")
  157. cell.NumFmt = "#,##0.00;(#,##0.00)"
  158. fvc.Equals(cell, "37947.75")
  159. cell.NumFmt = "0.00"
  160. fvc.Equals(cell, "37947.75")
  161. cell.NumFmt = "#,##0.00" // For the time being we're not doing
  162. // this comma formatting, so it'll fall back to the related
  163. // non-comma form.
  164. fvc.Equals(cell, "37947.75")
  165. cell.NumFmt = "#,##0 ;(#,##0)"
  166. fvc.Equals(cell, "37947")
  167. negativeCell.NumFmt = "#,##0 ;(#,##0)"
  168. fvc.Equals(negativeCell, "(37947)")
  169. cell.NumFmt = "#,##0 ;[red](#,##0)"
  170. fvc.Equals(cell, "37947")
  171. negativeCell.NumFmt = "#,##0 ;[red](#,##0)"
  172. fvc.Equals(negativeCell, "(37947)")
  173. negativeCell.NumFmt = "#,##0.00;(#,##0.00)"
  174. fvc.Equals(negativeCell, "(-37947.75)")
  175. cell.NumFmt = "0%"
  176. fvc.Equals(cell, "3794775%")
  177. cell.NumFmt = "0.00%"
  178. fvc.Equals(cell, "3794775.00%")
  179. cell.NumFmt = "0.00e+00"
  180. fvc.Equals(cell, "3.794775e+04")
  181. cell.NumFmt = "##0.0e+0" // This is wrong, but we'll use it for now.
  182. fvc.Equals(cell, "3.794775e+04")
  183. cell.NumFmt = "mm-dd-yy"
  184. fvc.Equals(cell, "11-22-03")
  185. cell.NumFmt = "d-mmm-yy"
  186. fvc.Equals(cell, "22-Nov-03")
  187. earlyCell.NumFmt = "d-mmm-yy"
  188. fvc.Equals(earlyCell, "1-Jan-00")
  189. cell.NumFmt = "d-mmm"
  190. fvc.Equals(cell, "22-Nov")
  191. earlyCell.NumFmt = "d-mmm"
  192. fvc.Equals(earlyCell, "1-Jan")
  193. cell.NumFmt = "mmm-yy"
  194. fvc.Equals(cell, "Nov-03")
  195. cell.NumFmt = "h:mm am/pm"
  196. fvc.Equals(cell, "6:00 pm")
  197. smallCell.NumFmt = "h:mm am/pm"
  198. fvc.Equals(smallCell, "12:10 am")
  199. cell.NumFmt = "h:mm:ss am/pm"
  200. fvc.Equals(cell, "6:00:00 pm")
  201. cell.NumFmt = "hh:mm:ss"
  202. fvc.Equals(cell, "18:00:00")
  203. smallCell.NumFmt = "h:mm:ss am/pm"
  204. fvc.Equals(smallCell, "12:10:04 am")
  205. cell.NumFmt = "h:mm"
  206. fvc.Equals(cell, "6:00")
  207. smallCell.NumFmt = "h:mm"
  208. fvc.Equals(smallCell, "12:10")
  209. smallCell.NumFmt = "hh:mm"
  210. fvc.Equals(smallCell, "00:10")
  211. cell.NumFmt = "h:mm:ss"
  212. fvc.Equals(cell, "6:00:00")
  213. cell.NumFmt = "hh:mm:ss"
  214. fvc.Equals(cell, "18:00:00")
  215. smallCell.NumFmt = "hh:mm:ss"
  216. fvc.Equals(smallCell, "00:10:04")
  217. smallCell.NumFmt = "h:mm:ss"
  218. fvc.Equals(smallCell, "12:10:04")
  219. cell.NumFmt = "m/d/yy h:mm"
  220. fvc.Equals(cell, "11/22/03 6:00")
  221. cell.NumFmt = "m/d/yy hh:mm"
  222. fvc.Equals(cell, "11/22/03 18:00")
  223. smallCell.NumFmt = "m/d/yy h:mm"
  224. fvc.Equals(smallCell, "12/30/99 12:10")
  225. smallCell.NumFmt = "m/d/yy hh:mm"
  226. fvc.Equals(smallCell, "12/30/99 00:10")
  227. earlyCell.NumFmt = "m/d/yy hh:mm"
  228. fvc.Equals(earlyCell, "1/1/00 02:24")
  229. earlyCell.NumFmt = "m/d/yy h:mm"
  230. fvc.Equals(earlyCell, "1/1/00 2:24")
  231. cell.NumFmt = "mm:ss"
  232. fvc.Equals(cell, "00:00")
  233. smallCell.NumFmt = "mm:ss"
  234. fvc.Equals(smallCell, "10:04")
  235. cell.NumFmt = "[hh]:mm:ss"
  236. fvc.Equals(cell, "18:00:00")
  237. cell.NumFmt = "[h]:mm:ss"
  238. fvc.Equals(cell, "6:00:00")
  239. smallCell.NumFmt = "[h]:mm:ss"
  240. fvc.Equals(smallCell, "10:04")
  241. const (
  242. expect1 = "0000.0086"
  243. expect2 = "1004.8000"
  244. format = "mmss.0000"
  245. tlen = len(format)
  246. )
  247. for i := 0; i < 3; i++ {
  248. tfmt := format[0 : tlen-i]
  249. cell.NumFmt = tfmt
  250. fvc.Equals(cell, expect1[0:tlen-i])
  251. smallCell.NumFmt = tfmt
  252. fvc.Equals(smallCell, expect2[0:tlen-i])
  253. }
  254. cell.NumFmt = "yyyy\\-mm\\-dd"
  255. fvc.Equals(cell, "2003\\-11\\-22")
  256. cell.NumFmt = "dd/mm/yyyy hh:mm:ss"
  257. fvc.Equals(cell, "22/11/2003 18:00:00")
  258. cell.NumFmt = "dd/mm/yy"
  259. fvc.Equals(cell, "22/11/03")
  260. earlyCell.NumFmt = "dd/mm/yy"
  261. fvc.Equals(earlyCell, "01/01/00")
  262. cell.NumFmt = "hh:mm:ss"
  263. fvc.Equals(cell, "18:00:00")
  264. smallCell.NumFmt = "hh:mm:ss"
  265. fvc.Equals(smallCell, "00:10:04")
  266. cell.NumFmt = "dd/mm/yy\\ hh:mm"
  267. fvc.Equals(cell, "22/11/03\\ 18:00")
  268. cell.NumFmt = "yyyy/mm/dd"
  269. fvc.Equals(cell, "2003/11/22")
  270. cell.NumFmt = "yy-mm-dd"
  271. fvc.Equals(cell, "03-11-22")
  272. cell.NumFmt = "d-mmm-yyyy"
  273. fvc.Equals(cell, "22-Nov-2003")
  274. earlyCell.NumFmt = "d-mmm-yyyy"
  275. fvc.Equals(earlyCell, "1-Jan-1900")
  276. cell.NumFmt = "m/d/yy"
  277. fvc.Equals(cell, "11/22/03")
  278. earlyCell.NumFmt = "m/d/yy"
  279. fvc.Equals(earlyCell, "1/1/00")
  280. cell.NumFmt = "m/d/yyyy"
  281. fvc.Equals(cell, "11/22/2003")
  282. earlyCell.NumFmt = "m/d/yyyy"
  283. fvc.Equals(earlyCell, "1/1/1900")
  284. cell.NumFmt = "dd-mmm-yyyy"
  285. fvc.Equals(cell, "22-Nov-2003")
  286. cell.NumFmt = "dd/mm/yyyy"
  287. fvc.Equals(cell, "22/11/2003")
  288. cell.NumFmt = "mm/dd/yy hh:mm am/pm"
  289. fvc.Equals(cell, "11/22/03 18:00 pm")
  290. cell.NumFmt = "mm/dd/yy h:mm am/pm"
  291. fvc.Equals(cell, "11/22/03 6:00 pm")
  292. cell.NumFmt = "mm/dd/yyyy hh:mm:ss"
  293. fvc.Equals(cell, "11/22/2003 18:00:00")
  294. smallCell.NumFmt = "mm/dd/yyyy hh:mm:ss"
  295. fvc.Equals(smallCell, "12/30/1899 00:10:04")
  296. cell.NumFmt = "yyyy-mm-dd hh:mm:ss"
  297. fvc.Equals(cell, "2003-11-22 18:00:00")
  298. smallCell.NumFmt = "yyyy-mm-dd hh:mm:ss"
  299. fvc.Equals(smallCell, "1899-12-30 00:10:04")
  300. cell.NumFmt = "mmmm d, yyyy"
  301. fvc.Equals(cell, "November 22, 2003")
  302. smallCell.NumFmt = "mmmm d, yyyy"
  303. fvc.Equals(smallCell, "December 30, 1899")
  304. cell.NumFmt = "dddd, mmmm dd, yyyy"
  305. fvc.Equals(cell, "Saturday, November 22, 2003")
  306. smallCell.NumFmt = "dddd, mmmm dd, yyyy"
  307. fvc.Equals(smallCell, "Saturday, December 30, 1899")
  308. }
  309. // test setters and getters
  310. func (s *CellSuite) TestSetterGetters(c *C) {
  311. cell := Cell{}
  312. cell.SetString("hello world")
  313. if val, err := cell.String(); err != nil {
  314. c.Error(err)
  315. } else {
  316. c.Assert(val, Equals, "hello world")
  317. }
  318. c.Assert(cell.Type(), Equals, CellTypeString)
  319. cell.SetInt(1024)
  320. intValue, _ := cell.Int()
  321. c.Assert(intValue, Equals, 1024)
  322. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  323. cell.SetInt64(1024)
  324. int64Value, _ := cell.Int64()
  325. c.Assert(int64Value, Equals, int64(1024))
  326. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  327. cell.SetFloat(1.024)
  328. float, _ := cell.Float()
  329. intValue, _ = cell.Int() // convert
  330. c.Assert(float, Equals, 1.024)
  331. c.Assert(intValue, Equals, 1)
  332. c.Assert(cell.Type(), Equals, CellTypeNumeric)
  333. cell.SetFormula("10+20")
  334. c.Assert(cell.Formula(), Equals, "10+20")
  335. c.Assert(cell.Type(), Equals, CellTypeFormula)
  336. }
  337. // TestOddInput is a regression test for #101. When the number format
  338. // was "@" (string), the input below caused a crash in strconv.ParseFloat.
  339. // The solution was to check if cell.Value was both a CellTypeString and
  340. // had a NumFmt of "general" or "@" and short-circuit FormattedValue() if so.
  341. func (s *CellSuite) TestOddInput(c *C) {
  342. cell := Cell{}
  343. odd := `[1],[12,"DATE NOT NULL DEFAULT '0000-00-00'"]`
  344. cell.Value = odd
  345. cell.NumFmt = "@"
  346. if val, err := cell.String(); err != nil {
  347. c.Error(err)
  348. } else {
  349. c.Assert(val, Equals, odd)
  350. }
  351. }
  352. // TestBool tests basic Bool getting and setting booleans.
  353. func (s *CellSuite) TestBool(c *C) {
  354. cell := Cell{}
  355. cell.SetBool(true)
  356. c.Assert(cell.Value, Equals, "1")
  357. c.Assert(cell.Bool(), Equals, true)
  358. cell.SetBool(false)
  359. c.Assert(cell.Value, Equals, "0")
  360. c.Assert(cell.Bool(), Equals, false)
  361. }
  362. // TestStringBool tests calling Bool on a non CellTypeBool value.
  363. func (s *CellSuite) TestStringBool(c *C) {
  364. cell := Cell{}
  365. cell.SetInt(0)
  366. c.Assert(cell.Bool(), Equals, false)
  367. cell.SetInt(1)
  368. c.Assert(cell.Bool(), Equals, true)
  369. cell.SetString("")
  370. c.Assert(cell.Bool(), Equals, false)
  371. cell.SetString("0")
  372. c.Assert(cell.Bool(), Equals, true)
  373. }