From 56d533fd3279f8d6c7e6f56a489e1b734abcb166 Mon Sep 17 00:00:00 2001 From: Kevin F Date: Tue, 24 Oct 2023 13:00:17 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20ExcelIO:=20bool=20&=20float=20write.=20Fi?= =?UTF-8?q?x=20exceljs:=20table=20postion=20write,=20cell=20value=20type?= =?UTF-8?q?=20read=20and=20write,=20confusing=20naming.=20Add=20scripts=20?= =?UTF-8?q?for=20fsspreadsheet=20write.=20:sparkles:=F0=9F=A4=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/FsSpreadsheet.ExcelIO/Cell.fs | 9 +- src/FsSpreadsheet.ExcelIO/FsExtensions.fs | 9 +- src/FsSpreadsheet.Exceljs/Cell.fs | 88 ++++++++++++++++ .../FsSpreadsheet.Exceljs.fsproj | 97 +++++++++--------- src/FsSpreadsheet.Exceljs/Table.fs | 29 ++---- src/FsSpreadsheet.Exceljs/Workbook.fs | 16 +-- src/FsSpreadsheet.Exceljs/Worksheet.fs | 78 ++------------ src/FsSpreadsheet.Exceljs/Xlsx.fs | 12 +-- src/FsSpreadsheet/Cells/FsCell.fs | 20 +++- .../DefaultIO.Tests.fs | 3 +- .../OpenXml/FsExtensions.fs | 2 +- .../TestObjects.fs | 16 +-- .../DefaultIO.Tests.fs | 8 +- .../FsSpreadsheet.Exceljs.Tests.csproj | 22 ++++ .../Workbook.Tests.fs | 28 ++--- tests/JS/Exceljs.js | 2 +- tests/TestUtils/DefaultTestObjects.fs | 8 +- .../TestFiles/Scripts/fsSpreadsheet.fsx | 17 ++- .../TestFiles/Scripts/fsSpreadsheet.js | 4 +- .../TestFiles/TestWorkbook_ClosedXML.xlsx | Bin 15958 -> 15955 bytes .../TestFiles/TestWorkbook_Excel.xlsx | Bin 16901 -> 16876 bytes .../TestFiles/TestWorkbook_FableExceljs.xlsx | Bin 10698 -> 10724 bytes .../TestWorkbook_FsSpreadsheet.js.xlsx | Bin 0 -> 10491 bytes .../TestWorkbook_FsSpreadsheet.net.xlsx | Bin 5327 -> 5314 bytes tests/TestUtils/TestUtils.fsproj | 9 +- 25 files changed, 272 insertions(+), 205 deletions(-) create mode 100644 src/FsSpreadsheet.Exceljs/Cell.fs create mode 100644 tests/FsSpreadsheet.Exceljs.Tests/FsSpreadsheet.Exceljs.Tests.csproj create mode 100644 tests/TestUtils/TestFiles/TestWorkbook_FsSpreadsheet.js.xlsx diff --git a/src/FsSpreadsheet.ExcelIO/Cell.fs b/src/FsSpreadsheet.ExcelIO/Cell.fs index 6840e9ff..06870a6c 100644 --- a/src/FsSpreadsheet.ExcelIO/Cell.fs +++ b/src/FsSpreadsheet.ExcelIO/Cell.fs @@ -161,9 +161,12 @@ module Cell = |> SharedStringTable.count |> string |> fun v -> {|DataType = Some CellValues.SharedString; Value = v; Format = None|} - | DataType.String -> {|DataType = Some CellValues.String; Value = value; Format = None|} - | DataType.Boolean -> {|DataType = Some CellValues.Boolean; Value = value; Format = None|} - | DataType.Number -> {|DataType = Some CellValues.Number; Value = value; Format = None|} + | DataType.String -> + {|DataType = Some CellValues.String; Value = value; Format = None|} + | DataType.Boolean -> + {|DataType = Some CellValues.Boolean; Value = System.Boolean.Parse value |> FsCellAux.boolConverter; Format = None|} + | DataType.Number -> + {|DataType = Some CellValues.Number; Value = value; Format = None|} | DataType.Date -> //let cellFormat = CellFormat(NumberFormatId = UInt32Value 19u, ApplyNumberFormat = BooleanValue true) let value = System.DateTime.Parse(value).ToOADate() |> string diff --git a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs index 1725d6d1..70e717b6 100644 --- a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs +++ b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs @@ -82,13 +82,10 @@ module FsExtensions = | _ -> () | Number -> try - cellValue <- int cellValueString + cellValue <- float cellValueString with | _ -> - try - cellValue <- float cellValueString - with - | _ -> () + () | Empty | String -> () //let dt, v = DataType.InferCellValue v FsCell.createWithDataType dt (int row) (int col) (cellValue) @@ -168,7 +165,7 @@ module FsExtensions = let cells = cells |> List.map (fun cell -> - Cell.fromValueWithDataType doc (uint32 cell.ColumnNumber) (uint32 cell.RowNumber) (cell.ValueAsString()) (cell.DataType) + FsCell.toXlsxCell doc cell ) let row = Row.create (uint32 row.Index) (Row.Spans.fromBoundaries min max) cells SheetData.appendRow row sd |> ignore diff --git a/src/FsSpreadsheet.Exceljs/Cell.fs b/src/FsSpreadsheet.Exceljs/Cell.fs new file mode 100644 index 00000000..6fec03d2 --- /dev/null +++ b/src/FsSpreadsheet.Exceljs/Cell.fs @@ -0,0 +1,88 @@ +namespace FsSpreadsheet.Exceljs + + +module JsCell = + + open Fable.Core + open Fable.Core.JsInterop + open FsSpreadsheet + open Fable.ExcelJs + + [] + let private log (obj:obj) = jsNative + + let writeFromFsCell (fsCell: FsCell) = + match fsCell.DataType with + | Boolean -> + fsCell.ValueAsBool() |> box |> Some + | Number -> + fsCell.ValueAsFloat() |> box |> Some + | Date -> + /// Here it will actually show the correct DateTime. But when writing, exceljs will apply local offset. + let dt = fsCell.ValueAsDateTime() |> System.DateTimeOffset + /// Therefore we add offset and it should work. + let dt = dt + dt.Offset |> box |> Some + dt + | String -> + fsCell.Value |> Some + | anyElse -> + let msg = sprintf "ValueType '%A' is not fully implemented in FsSpreadsheet and is handled as string input." anyElse + #if FABLE_COMPILER_JAVASCRIPT + log msg + #else + printfn "%s" msg + #endif + fsCell.Value |> box |> Some + + /// + /// `worksheetName`, `rowIndex` and `columnIndex` are only used for debugging. + /// + /// + /// + /// + /// + let readToFsCell worksheetName rowIndex columnIndex (jsCell: Cell) = + let t = enum(jsCell.``type``) + let fsadress = FsAddress(jsCell.address) + let createFscell = fun dt v -> FsCell(v,dt,address = fsadress) + let vTemp = string jsCell.value.Value + let fscell = + match t with + | ValueType.Boolean -> + let b = System.Boolean.Parse vTemp + createFscell DataType.Boolean b + | ValueType.Number -> float vTemp |> createFscell DataType.Number + | ValueType.Date -> + let dt = System.DateTime.Parse(vTemp).ToUniversalTime() + /// Without this step universal time get changed to local time? Exceljs tests will hit this. + /// + /// Expected item (from test object): C2 : Sat Oct 14 2023 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date + /// + /// Actual item (created here): C2 : Sat Oct 14 2023 02:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date + /// + /// But logging hour minute showed that the values were given correctly and needed to be reinitialized. + let dt = System.DateTime(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute, dt.Second) + dt |> createFscell DataType.Date + | ValueType.String -> vTemp |> createFscell DataType.String + | ValueType.Formula -> + match jsCell.formula with + | "TRUE()" -> + let b = true + createFscell DataType.Boolean b + | "FALSE()" -> + let b = false + createFscell DataType.Boolean b + | anyElse -> + let msg = sprintf "ValueType 'Format' (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse worksheetName rowIndex columnIndex + log msg + anyElse |> createFscell DataType.String + | ValueType.Hyperlink -> + //log (c.value.Value?text) + jsCell.value.Value?hyperlink |> createFscell DataType.String + | anyElse -> + let msg = sprintf "ValueType `%A` (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse vTemp worksheetName rowIndex columnIndex + log msg + vTemp |> createFscell DataType.String + fscell + + diff --git a/src/FsSpreadsheet.Exceljs/FsSpreadsheet.Exceljs.fsproj b/src/FsSpreadsheet.Exceljs/FsSpreadsheet.Exceljs.fsproj index 6fd50397..a568732c 100644 --- a/src/FsSpreadsheet.Exceljs/FsSpreadsheet.Exceljs.fsproj +++ b/src/FsSpreadsheet.Exceljs/FsSpreadsheet.Exceljs.fsproj @@ -1,52 +1,51 @@ - - - - Kevin Frey, Heinrich Lukas Weil, Oliver Maus, Kevin Schneider, Timo Mühlhaus - Excel IO Extensions for the FsSpreadsheet Datamodel in js environments using exceljs. - Spreadsheet creation and manipulation in FSharp - MIT - logo.png - F# FSharp spreadsheet Excel xlsx datascience fable fable-library fable-javascript - https://github.com/CSBiology/FsSpreadsheet - git - - - - net6.0 - true - - - + + + + Kevin Frey, Heinrich Lukas Weil, Oliver Maus, Kevin Schneider, Timo Mühlhaus + Excel IO Extensions for the FsSpreadsheet Datamodel in js environments using exceljs. + Spreadsheet creation and manipulation in FSharp + MIT + logo.png + F# FSharp spreadsheet Excel xlsx datascience fable fable-library fable-javascript + https://github.com/CSBiology/FsSpreadsheet + git + + + + net6.0 + true + + + \ true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FsSpreadsheet.Exceljs/Table.fs b/src/FsSpreadsheet.Exceljs/Table.fs index 3554fa6e..58359f08 100644 --- a/src/FsSpreadsheet.Exceljs/Table.fs +++ b/src/FsSpreadsheet.Exceljs/Table.fs @@ -10,7 +10,7 @@ module JsTable = [] let private log (obj:obj) = jsNative - let fromFsTable (fscellcollection: FsCellsCollection) (fsTable: FsTable) : Table = + let writeFromFsTable (fscellcollection: FsCellsCollection) (fsTable: FsTable) : Table = let fsColumns = fsTable.GetColumns fscellcollection let columns = if fsTable.ShowHeaderRow then @@ -24,36 +24,25 @@ module JsTable = [| for col in fsColumns do let cells = if fsTable.ShowHeaderRow then col.Cells |> Seq.tail else col.Cells - yield! cells |> Seq.mapi (fun i c -> - let rowValue = - match c.DataType with - | Boolean -> c.ValueAsBool() |> box - | Number -> c.ValueAsFloat() |> box - | Date -> c.ValueAsDateTime() |> box - | String -> c.Value |> box - | anyElse -> - let msg = sprintf "ValueType '%A' is not fully implemented in FsSpreadsheet and is handled as string input." anyElse - #if FABLE_COMPILER_JAVASCRIPT - log msg - #else - printfn "%s" msg - #endif - c.Value |> box - i+1, rowValue + yield! cells |> Seq.map (fun c -> + let rowValue = JsCell.writeFromFsCell c |> Option.get + c.Address.RowNumber, (c.Address.ColumnNumber, rowValue) ) |] |> Array.groupBy fst |> Array.sortBy fst |> Array.map (fun (_,arr) -> - arr |> Array.map snd + let m = arr |> Array.map snd |> Map + let row = [|fsTable.RangeAddress.FirstAddress.ColumnNumber .. fsTable.RangeAddress.FirstAddress.ColumnNumber + (columns.Length-1)|] + let row = row |> Array.map (fun i -> m.TryFind i |> box) + row ) let defaultStyle = {| - theme = "TableStyleMedium7" showRowStripes = true |} Table(fsTable.Name,fsTable.RangeAddress.Range,columns,rows,fsTable.Name,headerRow = fsTable.ShowHeaderRow, style = defaultStyle) - let fromJsTable(table:ITableRef) = + let readToFsTable(table:ITableRef) = let table = table.table.Value let tableRef = table.tableRef |> FsRangeAddress let tableName = if isNull table.displayName then table.name else table.displayName diff --git a/src/FsSpreadsheet.Exceljs/Workbook.fs b/src/FsSpreadsheet.Exceljs/Workbook.fs index 6c569e03..a53c3d2e 100644 --- a/src/FsSpreadsheet.Exceljs/Workbook.fs +++ b/src/FsSpreadsheet.Exceljs/Workbook.fs @@ -13,15 +13,15 @@ module JsWorkbook = [] let private log (obj:obj) = jsNative - let toFsWorkbook (jswb: Workbook) = - let fswb = new FsWorkbook() - for jsws in jswb.worksheets do - JsWorksheet.addJsWorksheet fswb jsws - fswb - - let fromFsWorkbook (fswb: FsWorkbook) = + let writeFromFsWorkbook (fswb: FsWorkbook) = let jswb = ExcelJs.Excel.Workbook() jswb?_themes <- Aux.theme1 for fsws in fswb.GetWorksheets() do - JsWorksheet.addFsWorksheet jswb fsws + JsWorksheet.writeFromFsWorksheet jswb fsws jswb + + let readToFsWorkbook (jswb: Workbook) = + let fswb = new FsWorkbook() + for jsws in jswb.worksheets do + JsWorksheet.readToFsWorksheet fswb jsws + fswb diff --git a/src/FsSpreadsheet.Exceljs/Worksheet.fs b/src/FsSpreadsheet.Exceljs/Worksheet.fs index ed84e4c2..ecbcfb09 100644 --- a/src/FsSpreadsheet.Exceljs/Worksheet.fs +++ b/src/FsSpreadsheet.Exceljs/Worksheet.fs @@ -10,92 +10,32 @@ module JsWorksheet = open FsSpreadsheet open Fable.ExcelJs - open Fable.Core.JsInterop - let boolConverter (bool:bool) = - match bool with | true -> "1" | false -> "0" - - let addFsWorksheet (wb: Workbook) (fsws:FsWorksheet) : unit = + let writeFromFsWorksheet (wb: Workbook) (fsws:FsWorksheet) : unit = fsws.RescanRows() let rows = fsws.Rows |> Seq.map (fun x -> x.Cells) let ws = wb.addWorksheet(fsws.Name) // due to the design of fsspreadsheet this might overwrite some of the stuff from tables, // but as it should be the same, this is only a performance sink. for row in rows do - for cell in row do - let c = ws.getCell(cell.Address.Address) - match cell.DataType with - | Boolean -> - c.value <- cell.ValueAsBool() |> boolConverter |> box |> Some - | Number -> - c.value <- cell.ValueAsFloat() |> box |> Some - | Date -> - c.value <- cell.ValueAsDateTime() |> box |> Some - | String -> - c.value <- cell.Value |> box |> Some - | anyElse -> - let msg = sprintf "ValueType '%A' is not fully implemented in FsSpreadsheet and is handled as string input." anyElse - #if FABLE_COMPILER_JAVASCRIPT - log msg - #else - printfn "%s" msg - #endif - c.value <- cell.Value |> box |> Some - let tables = fsws.Tables |> Seq.map (fun table -> JsTable.fromFsTable fsws.CellCollection table) + for fsCell in row do + let jsCell = ws.getCell(fsCell.Address.Address) + jsCell.value <- JsCell.writeFromFsCell fsCell + let tables = fsws.Tables |> Seq.map (fun table -> JsTable.writeFromFsTable fsws.CellCollection table) for table in tables do ws.addTable(table) |> ignore - let addJsWorksheet (wb: FsWorkbook) (jsws: Worksheet) : unit = + let readToFsWorksheet (wb: FsWorkbook) (jsws: Worksheet) : unit = let fsws = FsWorksheet(jsws.name) jsws.eachRow(fun (row, rowIndex) -> row.eachCell(fun (c, columnIndex) -> if c.value.IsSome then - let t = enum(c.``type``) - let fsadress = FsAddress(c.address) - let createFscell = fun dt v -> FsCell(v,dt,address = fsadress) - let vTemp = string c.value.Value - let fscell = - match t with - | ValueType.Boolean -> - let b = System.Boolean.Parse vTemp |> boolConverter - createFscell DataType.Boolean b - | ValueType.Number -> float vTemp |> createFscell DataType.Number - | ValueType.Date -> - let dt = System.DateTime.Parse(vTemp).ToUniversalTime() - /// Without this step universal time get changed to local time? Exceljs tests will hit this. - /// - /// Expected item (from test object): C2 : Sat Oct 14 2023 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date - /// - /// Actual item (created here): C2 : Sat Oct 14 2023 02:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) | Date - /// - /// But logging hour minute showed that the values were given correctly and needed to be reinitialized. - let dt = System.DateTime(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute, dt.Second) - dt |> createFscell DataType.Date - | ValueType.String -> vTemp |> createFscell DataType.String - | ValueType.Formula -> - match c.formula with - | "TRUE()" -> - let b = true |> boolConverter - createFscell DataType.Boolean b - | "FALSE()" -> - let b = false |> boolConverter - createFscell DataType.Boolean b - | anyElse -> - let msg = sprintf "ValueType 'Format' (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse jsws.name rowIndex columnIndex - log msg - anyElse |> createFscell DataType.String - | ValueType.Hyperlink -> - //log (c.value.Value?text) - c.value.Value?hyperlink |> createFscell DataType.String - | anyElse -> - let msg = sprintf "ValueType `%A` (%s) is not fully implemented in FsSpreadsheet and is handled as string input. In %s: (%i,%i)" anyElse vTemp jsws.name rowIndex columnIndex - log msg - vTemp |> createFscell DataType.String - fsws.AddCell(fscell) |> ignore + let fsCell = JsCell.readToFsCell jsws.name rowIndex columnIndex c + fsws.AddCell(fsCell) |> ignore ) ) for jstableref in jsws.getTables() do - let table = JsTable.fromJsTable jstableref + let table = JsTable.readToFsTable jstableref fsws.AddTable table |> ignore fsws.RescanRows() wb.AddWorksheet(fsws) \ No newline at end of file diff --git a/src/FsSpreadsheet.Exceljs/Xlsx.fs b/src/FsSpreadsheet.Exceljs/Xlsx.fs index 850733de..aa5af836 100644 --- a/src/FsSpreadsheet.Exceljs/Xlsx.fs +++ b/src/FsSpreadsheet.Exceljs/Xlsx.fs @@ -14,7 +14,7 @@ type Xlsx = promise { let wb = ExcelJs.Excel.Workbook() do! wb.xlsx.readFile(path) - let fswb = JsWorkbook.toFsWorkbook wb + let fswb = JsWorkbook.readToFsWorkbook wb return fswb } @@ -22,7 +22,7 @@ type Xlsx = promise { let wb = ExcelJs.Excel.Workbook() do! wb.xlsx.read stream - return JsWorkbook.toFsWorkbook wb + return JsWorkbook.readToFsWorkbook wb } static member fromBytes (bytes: byte []) : Promise = @@ -30,20 +30,20 @@ type Xlsx = let wb = ExcelJs.Excel.Workbook() let uint8 = Fable.Core.JS.Constructors.Uint8Array.Create bytes do! wb.xlsx.load(uint8.buffer) - return JsWorkbook.toFsWorkbook wb + return JsWorkbook.readToFsWorkbook wb } static member toFile (path: string) (wb:FsWorkbook) : Promise = - let jswb = JsWorkbook.fromFsWorkbook wb + let jswb = JsWorkbook.writeFromFsWorkbook wb jswb.xlsx.writeFile(path) static member toStream (stream: System.IO.Stream) (wb:FsWorkbook) : Promise = - let jswb = JsWorkbook.fromFsWorkbook wb + let jswb = JsWorkbook.writeFromFsWorkbook wb jswb.xlsx.write(stream) static member toBytes (wb:FsWorkbook) : Promise = promise { - let jswb = JsWorkbook.fromFsWorkbook wb + let jswb = JsWorkbook.writeFromFsWorkbook wb let buffer = jswb.xlsx.writeBuffer() return !!buffer } diff --git a/src/FsSpreadsheet/Cells/FsCell.fs b/src/FsSpreadsheet/Cells/FsCell.fs index df8f0f05..d0a5714b 100644 --- a/src/FsSpreadsheet/Cells/FsCell.fs +++ b/src/FsSpreadsheet/Cells/FsCell.fs @@ -54,6 +54,11 @@ type DataType = /// Creates an FsCell of `DataType` dataType, with value of type `string`, and `FsAddress` address. /// +module FsCellAux = + + let boolConverter (bool:bool) = + match bool with | true -> "1" | false -> "0" + [] type FsCell (value : obj, ?dataType : DataType, ?address : FsAddress) = @@ -233,8 +238,16 @@ type FsCell (value : obj, ?dataType : DataType, ?address : FsAddress) = /// /// Gets the value as string /// - member self.ValueAsString() = - self.Value.ToString() + member self.ValueAsString() : string = + let v = self.Value + match self.DataType with + | DataType.String | DataType.Date | DataType.Boolean | DataType.Empty -> + v.ToString() + | Number -> + // Example: 4.123: + // - (4.123)ToString() will parse floats in germany to "4,123" which is not allowed by Excel. + // - string(4.123) will parse floats in germany to "4.123" which is allowed by Excel. + string v /// /// Gets the value as string @@ -417,9 +430,6 @@ type FsCell (value : obj, ?dataType : DataType, ?address : FsAddress) = this.RowNumber = other.RowNumber |] |> Seq.forall (fun x -> x=true) - if not r then - printfn "[VALUE] %A, %A" this.Value other.Value - printfn "[DATATYPE] %O, %O" this.DataType other.DataType r diff --git a/tests/FsSpreadsheet.ExcelIO.Tests/DefaultIO.Tests.fs b/tests/FsSpreadsheet.ExcelIO.Tests/DefaultIO.Tests.fs index 989d1f21..65a7bbec 100644 --- a/tests/FsSpreadsheet.ExcelIO.Tests/DefaultIO.Tests.fs +++ b/tests/FsSpreadsheet.ExcelIO.Tests/DefaultIO.Tests.fs @@ -20,7 +20,7 @@ let tests_Read = testList "Read" [ testCase "Excel" <| fun _ -> let wb = readFromTestFile DefaultTestObject.TestFiles.Excel Expect.isDefaultTestObject wb - testCase "Libre" <| fun _ -> + ptestCase "Libre" <| fun _ -> let wb = readFromTestFile DefaultTestObject.TestFiles.Libre Expect.isDefaultTestObject wb testCase "FableExceljs" <| fun _ -> @@ -31,6 +31,7 @@ let tests_Read = testList "Read" [ Expect.isDefaultTestObject wb testCase "FsSpreadsheet" <| fun _ -> let wb = readFromTestFile DefaultTestObject.TestFiles.FsSpreadsheetNET + wb.GetWorksheets().[0].GetCellAt(5,1) |> fun x -> (x.Value, x.DataType) |> printfn "%A" Expect.isDefaultTestObject wb ] diff --git a/tests/FsSpreadsheet.ExcelIO.Tests/OpenXml/FsExtensions.fs b/tests/FsSpreadsheet.ExcelIO.Tests/OpenXml/FsExtensions.fs index 82881b6a..5ffc6d5c 100644 --- a/tests/FsSpreadsheet.ExcelIO.Tests/OpenXml/FsExtensions.fs +++ b/tests/FsSpreadsheet.ExcelIO.Tests/OpenXml/FsExtensions.fs @@ -120,7 +120,7 @@ let fsExtensionTests = Expect.equal d DataType.String "DataType is not DataType.String" testCase "is equal to dummyFsWorkbook in sheet2, cellC7 value" <| fun _ -> let v = (FsWorksheet.getCellAt 7 3 fsWorksheet2FromStream).Value - Expect.equal v 7 "value is not equal" + Expect.equal v 7. "value is not equal" testCase "is equal to dummyFsWorkbook in sheet2, cellC7 address" <| fun _ -> let a = (FsWorksheet.getCellAt 7 3 fsWorksheet2FromStream).Address.Address Expect.equal a "C7" "address is not equal" diff --git a/tests/FsSpreadsheet.ExcelIO.Tests/TestObjects.fs b/tests/FsSpreadsheet.ExcelIO.Tests/TestObjects.fs index 0be08089..41c08507 100644 --- a/tests/FsSpreadsheet.ExcelIO.Tests/TestObjects.fs +++ b/tests/FsSpreadsheet.ExcelIO.Tests/TestObjects.fs @@ -26,15 +26,15 @@ let sheet1() = let sheet2() = let ws = new FsWorksheet(sheet2Name) [ - FsCell.createWithDataType DataType.Number 1 1 1 - FsCell.createWithDataType DataType.Number 1 2 2 - FsCell.createWithDataType DataType.Number 1 3 3 - FsCell.createWithDataType DataType.Number 1 4 4 + FsCell.createWithDataType DataType.Number 1 1 1. + FsCell.createWithDataType DataType.Number 1 2 2. + FsCell.createWithDataType DataType.Number 1 3 3. + FsCell.createWithDataType DataType.Number 1 4 4. - FsCell.createWithDataType DataType.Number 2 1 5 - FsCell.createWithDataType DataType.Number 2 2 6 - FsCell.createWithDataType DataType.Number 2 3 7 - FsCell.createWithDataType DataType.Number 2 4 8 + FsCell.createWithDataType DataType.Number 2 1 5. + FsCell.createWithDataType DataType.Number 2 2 6. + FsCell.createWithDataType DataType.Number 2 3 7. + FsCell.createWithDataType DataType.Number 2 4 8. ] |> List.iter (fun c -> ws.Row(c.RowNumber).[c.ColumnNumber].SetValueAs c.Value) ws \ No newline at end of file diff --git a/tests/FsSpreadsheet.Exceljs.Tests/DefaultIO.Tests.fs b/tests/FsSpreadsheet.Exceljs.Tests/DefaultIO.Tests.fs index 3b1604c7..660669c2 100644 --- a/tests/FsSpreadsheet.Exceljs.Tests/DefaultIO.Tests.fs +++ b/tests/FsSpreadsheet.Exceljs.Tests/DefaultIO.Tests.fs @@ -13,7 +13,7 @@ let tests_Read = testList "Read" [ let! wb = readFromTestFile DefaultTestObject.TestFiles.Excel |> Async.AwaitPromise Expect.isDefaultTestObject wb } - testCaseAsync "Libre" <| async { + ptestCaseAsync "Libre" <| async { let! wb = readFromTestFile DefaultTestObject.TestFiles.Libre |> Async.AwaitPromise Expect.isDefaultTestObject wb } @@ -25,8 +25,12 @@ let tests_Read = testList "Read" [ let! wb = readFromTestFile DefaultTestObject.TestFiles.ClosedXML |> Async.AwaitPromise Expect.isDefaultTestObject wb } - testCaseAsync "FsSpreadsheet" <| async { + testCaseAsync "FsSpreadsheetNET" <| async { let! wb = readFromTestFile DefaultTestObject.TestFiles.FsSpreadsheetNET |> Async.AwaitPromise Expect.isDefaultTestObject wb } + testCaseAsync "FsSpreadsheetJS" <| async { + let! wb = readFromTestFile DefaultTestObject.TestFiles.FsSpreadsheetJS |> Async.AwaitPromise + Expect.isDefaultTestObject wb + } ] \ No newline at end of file diff --git a/tests/FsSpreadsheet.Exceljs.Tests/FsSpreadsheet.Exceljs.Tests.csproj b/tests/FsSpreadsheet.Exceljs.Tests/FsSpreadsheet.Exceljs.Tests.csproj new file mode 100644 index 00000000..7851ed66 --- /dev/null +++ b/tests/FsSpreadsheet.Exceljs.Tests/FsSpreadsheet.Exceljs.Tests.csproj @@ -0,0 +1,22 @@ + + + + Exe + net6.0 + false + + + + + + + + + + + + + + + + diff --git a/tests/FsSpreadsheet.Exceljs.Tests/Workbook.Tests.fs b/tests/FsSpreadsheet.Exceljs.Tests/Workbook.Tests.fs index 46ea3795..7ab1e3c6 100644 --- a/tests/FsSpreadsheet.Exceljs.Tests/Workbook.Tests.fs +++ b/tests/FsSpreadsheet.Exceljs.Tests/Workbook.Tests.fs @@ -5,6 +5,8 @@ open Fable.ExcelJs open FsSpreadsheet.Exceljs open FsSpreadsheet +open Fable.Core + module Helper = open Fable.Core @@ -18,7 +20,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ testCase "empty" <| fun _ -> let jswb = ExcelJs.Excel.Workbook() Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb Expect.passWithMsg "Convert to fswb" let fswsList = fswb.GetWorksheets() let jswsList = jswb.worksheets @@ -27,7 +29,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ let jswb = ExcelJs.Excel.Workbook() let _ = jswb.addWorksheet("My Awesome Worksheet") Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb Expect.passWithMsg "Convert to fswb" let jswsList = jswb.worksheets let fswsList = fswb.GetWorksheets() @@ -39,7 +41,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ let _ = jswb.addWorksheet("My Best Worksheet") let _ = jswb.addWorksheet("My Nice Worksheet") Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb Expect.passWithMsg "Convert to fswb" let jswsList = jswb.worksheets let fswsList = fswb.GetWorksheets() @@ -57,7 +59,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ let table = Table("My_Awesome_Table", "B1", tableColumns, [||]) let _ = jsws.addTable(table) Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb Expect.passWithMsg "Convert to fswb" let fsTables_a = fswb.GetWorksheets().[0].Tables let fsTables_b = fswb.GetTables() @@ -87,7 +89,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ let table = Table("My_Awesome_Table", "B1", tableColumns, rows) let _ = jsws.addTable(table) Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb Expect.passWithMsg "Convert to fswb" let fsTables = fswb.GetTables() Expect.hasLength (jsws.getTables()) 1 "js table count" @@ -107,7 +109,7 @@ let private tests_toFsWorkbook = testList "toFsWorkbook" [ let table = Table("My_Awesome_Table", "B1", tableColumns, rows) let _ = jsws.addTable(table) Expect.passWithMsg "Create jswb" - let fswb = JsWorkbook.toFsWorkbook jswb + let fswb = JsWorkbook.readToFsWorkbook jswb let getCellValue (address: string) = let ws = fswb.GetWorksheetAt 1 let range = FsAddress(address) @@ -132,7 +134,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ testCase "empty" <| fun _ -> let fswb = new FsWorkbook() Expect.passWithMsg "Create fswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb Expect.passWithMsg "Convert to jswb" let fswsList = fswb.GetWorksheets() let jswsList = jswb.worksheets @@ -141,7 +143,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ let fswb = new FsWorkbook() let _ = fswb.InitWorksheet("My Awesome Worksheet") Expect.passWithMsg "Create fswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb Expect.passWithMsg "Convert to jswb" let fswsList = fswb.GetWorksheets() let jswsList = jswb.worksheets @@ -154,7 +156,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ let _ = fswb.InitWorksheet("My cool Worksheet") let _ = fswb.InitWorksheet("My wow Worksheet") Expect.passWithMsg "Create fswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb Expect.passWithMsg "Convert to jswb" let fswsList = fswb.GetWorksheets() let jswsList = jswb.worksheets @@ -171,7 +173,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ let t = FsTable("My_New_Table", FsRangeAddress("B1:C1")) let _ = fsws.AddTable(t) Expect.passWithMsg "Create jswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb Expect.passWithMsg "Convert to fswb" let jsws = jswb.worksheets.[0] Expect.equal jsws.name "My Awesome Worksheet" "ws name" @@ -198,7 +200,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ let t = FsTable("My_New_Table", FsRangeAddress("B1:D3")) let _ = fsws.AddTable(t) Expect.passWithMsg "Create jswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb Expect.passWithMsg "Convert to fswb" let jsws = jswb.worksheets.[0] Expect.equal jsws.name "My Awesome Worksheet" "ws name" @@ -227,7 +229,7 @@ let tests_toJsWorkbook = testList "toJsWorkbook" [ let _ = fsws.AddTable(t) fsws.RescanRows() Expect.passWithMsg "Create jswb" - let jswb = JsWorkbook.fromFsWorkbook fswb + let jswb = JsWorkbook.writeFromFsWorkbook fswb let jstable = jswb.worksheets.[0].getTables().[0].table.Value let row0 = jstable.rows.[0] let row1 = jstable.rows.[1] @@ -279,7 +281,7 @@ open Fable.Core let tests_xlsx = testList "xlsx" [ testList "read" [ - ftestCaseAsync "isa.assay.xlsx" <| async { + testCaseAsync "isa.assay.xlsx" <| async { let! fswb = Xlsx.fromXlsxFile("./tests/JS/TestFiles/isa.assay.xlsx") |> Async.AwaitPromise Expect.equal (fswb.GetWorksheets().Count) 5 "Count" } diff --git a/tests/JS/Exceljs.js b/tests/JS/Exceljs.js index 49ec9388..3463ef35 100644 --- a/tests/JS/Exceljs.js +++ b/tests/JS/Exceljs.js @@ -3,7 +3,7 @@ import { Xlsx } from './FsSpreadsheet.Exceljs/Xlsx.js'; import { FsWorkbook } from "./FsSpreadsheet.Exceljs/FsSpreadsheet/FsWorkbook.js"; import { FsRangeAddress_$ctor_Z721C83C5, FsRangeAddress__get_Range } from "./FsSpreadsheet.Exceljs/FsSpreadsheet/Ranges/FsRangeAddress.js"; import { FsTable } from "./FsSpreadsheet.Exceljs/FsSpreadsheet/Tables/FsTable.js"; -import { fromFsWorkbook, toFsWorkbook } from "./FsSpreadsheet.Exceljs/Workbook.js"; +import { writeFromFsWorkbook, readToFsWorkbook } from "./FsSpreadsheet.Exceljs/Workbook.js"; describe('FsSpreadsheet.Exceljs', function () { describe('read', function () { diff --git a/tests/TestUtils/DefaultTestObjects.fs b/tests/TestUtils/DefaultTestObjects.fs index cbc4eea8..c8f1df31 100644 --- a/tests/TestUtils/DefaultTestObjects.fs +++ b/tests/TestUtils/DefaultTestObjects.fs @@ -43,7 +43,7 @@ module ExpectedRows = row let firstRow(range: string) cc = let row = FsRow(FsRangeAddress(range),cc) - row[1].SetValueAs 1 + row[1].SetValueAs 1. row[2].SetValueAs "Hello" row[3].SetValueAs (System.DateTime(2023,10,14,0,0,0)) row[4].SetValueAs true @@ -52,7 +52,7 @@ module ExpectedRows = row let secondRow(range:string) cc = let row = FsRow(FsRangeAddress(range),cc) - row[1].SetValueAs 2 + row[1].SetValueAs 2. row[2].SetValueAs "World" row[3].SetValueAs (System.DateTime(2023,10,15, 18,0,0)) row[4].SetValueAs false @@ -60,14 +60,14 @@ module ExpectedRows = row let thirdRow(range:string) cc = let row = FsRow(FsRangeAddress(range),cc) - row[1].SetValueAs 3 + row[1].SetValueAs 3. row[2].SetValueAs "Bye" row[3].SetValueAs (System.DateTime(2023,10,16, 20,0,0)) row[4].SetValueAs true row let fourthRow(range:string) cc = let row = FsRow(FsRangeAddress(range),cc) - row[1].SetValueAs 4 + row[1].SetValueAs 4.269 row[2].SetValueAs "Outer Space" row[3].SetValueAs (System.DateTime(2023,10,17,0,0,0)) row[4].SetValueAs false diff --git a/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.fsx b/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.fsx index 0e7349d7..81513451 100644 --- a/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.fsx +++ b/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.fsx @@ -1,16 +1,25 @@ -#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Release\net6.0\DocumentFormat.OpenXml.dll" -#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Release\net6.0\FsSpreadsheet.dll" -#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Release\net6.0\FsSpreadsheet.ExcelIO.dll" -#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Release\net6.0\System.IO.Packaging.dll" +#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Debug\net6.0\DocumentFormat.OpenXml.dll" +#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Debug\net6.0\FsSpreadsheet.dll" +#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Debug\net6.0\FsSpreadsheet.ExcelIO.dll" +#r @"..\..\..\FsSpreadsheet.ExcelIO.Tests\bin\Debug\net6.0\System.IO.Packaging.dll" open FsSpreadsheet open FsSpreadsheet.ExcelIO +open DocumentFormat.OpenXml.Spreadsheet +open DocumentFormat.OpenXml let inputPath = @"../TestWorkbook_Excel.xlsx" let outputPath = @"../TestWorkbook_FsSpreadsheet.net.xlsx" let wb = FsWorkbook.fromXlsxFile (inputPath) +// wb.GetWorksheets().[0].GetCellAt(5,1) |> fun x -> (x.Value, x.DataType) |> printfn "%A" + +// let r = wb.GetWorksheets().[0].GetCellAt(5,1).Value |> string + +// Cell(DataType = EnumValue(CellValues.Number), CellValue = CellValue(r)).InnerText + +// for i in r do printfn "%A" i wb.ToFile(outputPath) diff --git a/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.js b/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.js index 11ed0b0f..12b9264a 100644 --- a/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.js +++ b/tests/TestUtils/TestFiles/Scripts/fsSpreadsheet.js @@ -6,8 +6,8 @@ export const outputPath = "../TestWorkbook_FsSpreadsheet.js.xlsx"; async function run() { let wb = await Xlsx.fromXlsxFile(inputPath) - console.log(wb) - // await Xlsx.toFile(wb) + // console.log(wb) + Xlsx.toFile(outputPath, wb) } run(); diff --git a/tests/TestUtils/TestFiles/TestWorkbook_ClosedXML.xlsx b/tests/TestUtils/TestFiles/TestWorkbook_ClosedXML.xlsx index 9df17ab708b9f73a22b4f47d63b37862a981ac3d..09270a7e176399fc5531f2e8014914320f09d132 100644 GIT binary patch delta 8025 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

yQsLT&8{O}CLaLo~t`A$n!g3rc_JI(gnM z?o7{fZg*z$&Zjc{U*)fYh}$WIib|o_UF~%DW8FJu;S+E!@1AhfCnHa;;eteVfB!t?~Hr>bd9%V z`Sk8#9^<9rT(^>3PVWbKpZ2A8_v!XX_8erM-KI2Mgmsftn94x_eue!~q(A6<{~%yf z8hN!jYgf?YniuI#wxKoddQlUz1Y7O8HgDef_ig!(>P()N=~p+#Vf~IKHULz;A2~NH za)x>oDbG7;ZJ<^v5`e0KQx7}pGn2~t*B~@*4IGH5j7$jPCPsSy&%`Sgnlt*h02`e| z{&a}hxTn=q_E6`qkN@~&k*18BoR{p<2x8thIt>M9^}!+}l5tdPh5LQi zQnB&So3P-KCLsSPwlEo_0?W!AIeBC0TKMDOP>i0q#>QMs2D{L%G zss*6?41tX$VJktFWOEVg9CrR-!x9wKzf%zLJjy`^Z^CYOPFC@4#3%&_)=iL2HGA;i zy)4y+rzB`Rlr-6Zr3Pg@5Rzrcg&SN9s>`3I{WkfrCC{6eXSn4sDL4idJcJ;D;?m~h zbO37O0k#<~-CILRmj#~piK?V3=b>k7uc%8wL3YA{d8#<}vUKkz_si;_zRf@!?E+3W z=2^OJt6}>ZtrjBLNTC>4D5(xv3LB8`QYx`>+qOh=%8o_Xxu;$EUTH1AI*X7h@wjAk z!**)GLs7Gi>2I?8BBKS%az5eSnEhA$C^n{?bdkcN3*6>@?cF2N^y@pr566e)RV4B! zKoQZs^NU}WhvmM>la1Tq+$9;$F!g@4eaOfWQp71-?;)hAmt&`d28cQKuwzQqV0-5+ zD(aS2Qp-5>6_aZ)VrzJ&3PA%GqwFO%?G0{Z+Qq*G=4&z^?Tx-oTw8UBbY2Y^E=-|U zs>L#3enX1xij-!oXPlhZx`fS423s??Ef>Qd<2KWK#h9t$SfBcjusi;4QY32aQ8g|V z3%Nv}2{rv}Eu?+w2q1bK&tDbzQrc22-%`2oGgSFmIIlhGi}fd_9YG$L@#^la$0qrn zQd;-&e%mtxC2R2F1uls!Rb{u^kkG(@xr>0Lgas@7N4#byd%hLNW?*XmksvC6@^z+w z2!=p8&ftK=1B`&h51Y8RS=jOk56<8iaqfK#7M#Or9ZRJNAQuCpT9PFP4aXRs`RHL} zqI2}j6YuK_&<+0h+UkwGWGNWiL&S1v4ebhEeg8$e`Zw!4-pQQk@US|T+VwwqHlUIJ zIo$=t@+rb$zVG-z9Ee1qWdTf*f6jdVxApVh`~BZb6B+c29~Z>Wk4y63-QoWyfr7F^ z`?n~NAD8&Qn@ImBask!yGZFu@*(8U8`uKm7?;{`3Ek7;E|0Q=QD762We;@(z3h+TY zgIoo~V5%uVBb3CTNrBHWg_Q3@8W58pCdofe1_K3!^B)hVQ-Qju@IVfNn8g2}`TvQa zLFs~G?+Yvoib8LLh=rJl|M>^swOIf0LOPI%kT7&2C|^hjIt8>Y#PY8=gV2SE-|rZO LX%Tq&{w4n(c5n3@ delta 7983 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 D>&6Jh delta 6974 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

-gNL|{wTr2^LL!ea+6be7$=DAg73}* zV(I>sF=7PIJ!scG{ZrpYBvC#PV9OpUtEbIOrtbCJ63f!u^fC8 z&{tg{%7z|~>9qiLtXhe#tF$~S#B|2XGG|xE!B<@@%0Q)pYxUW;eW{;g z$1QBDbbHvN!WWuxl<5`#R?Fl|3p~{IrHA`4bcp*dWtwyjZ^pnT)Z_w(_y?6lSV&~J zn4Rmm+?}?o?iX+!?B)Iki(p#!4>)@5aN~|>tTpm;%*=1#X^(@k5fAc_A2yM9bid)V z37&T1!{mWNhx+fFJ-fBh`T8=+zSih~FtfHqJL~Cb?Rk5ASoc(@+mVR*q-rA$IizqN zmCTlTCu~$|t#yd*POW~+{FMo3L2w(l#Jv&!?ZU@eN&^IkHcIhO{bx@6Gzk8)grK)l zTvY$WWPjzz{}i8IuAvZVF6w_0ga1{JC5C1bQ$pos@u~h9qUaG2i2l6?f)aE@nw9Dw zi9I#J`H%WHD6Wh+A~F+HMMf6Ujv2ZrLj^6B5e8X9f5~WpETBBH5JUnFsJpBzXb4&_ zD~lu{i~yAprhwu=@TvZR|0xb7_>Z>1P*Dgo)ju2g$)EWDQGbB?LZpy?iz6UFcf@I- NGZ1{#UCDoa@n0B50i6H< diff --git a/tests/TestUtils/TestFiles/TestWorkbook_FableExceljs.xlsx b/tests/TestUtils/TestFiles/TestWorkbook_FableExceljs.xlsx index 28fc364ec9e2d909eb3584f3ba98a149cb1fa3de..85dbdad52a28ad48f349b7ae02f08786a1cd056d 100644 GIT binary patch delta 6205 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 Mj8D<#@BhaC0hq@(<^TWy delta 6212 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 Bcz6H+ literal 0 HcmV?d00001 diff --git a/tests/TestUtils/TestFiles/TestWorkbook_FsSpreadsheet.net.xlsx b/tests/TestUtils/TestFiles/TestWorkbook_FsSpreadsheet.net.xlsx index 40c1cd02610284407a12a965a97488b784d0abf4..85fdd4c9d133ca4e9f4c13153ab52a60a5cac827 100644 GIT binary patch delta 2722 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 W5rz{4652(k2^7JOKtm6(U;Y6P@SB?e delta 2705 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 diff --git a/tests/TestUtils/TestUtils.fsproj b/tests/TestUtils/TestUtils.fsproj index cc653788..476f1794 100644 --- a/tests/TestUtils/TestUtils.fsproj +++ b/tests/TestUtils/TestUtils.fsproj @@ -18,9 +18,12 @@ Always - - Always - + + Always + + + Always +