summaryrefslogtreecommitdiffstats
path: root/basic/qa/cppunit
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--basic/qa/cppunit/_test_asserts.bas66
-rw-r--r--basic/qa/cppunit/_test_asserts.vb67
-rw-r--r--basic/qa/cppunit/basic_coverage.cxx126
-rw-r--r--basic/qa/cppunit/basictest.cxx125
-rw-r--r--basic/qa/cppunit/basictest.hxx52
-rw-r--r--basic/qa/cppunit/test_append.cxx78
-rw-r--r--basic/qa/cppunit/test_compiler_checks.cxx117
-rw-r--r--basic/qa/cppunit/test_global_array.cxx86
-rw-r--r--basic/qa/cppunit/test_global_as_new.cxx83
-rw-r--r--basic/qa/cppunit/test_language_conditionals.cxx166
-rw-r--r--basic/qa/cppunit/test_nested_struct.cxx323
-rw-r--r--basic/qa/cppunit/test_scanner.cxx1165
-rw-r--r--basic/qa/cppunit/test_vba.cxx269
13 files changed, 2723 insertions, 0 deletions
diff --git a/basic/qa/cppunit/_test_asserts.bas b/basic/qa/cppunit/_test_asserts.bas
new file mode 100644
index 000000000..51442a059
--- /dev/null
+++ b/basic/qa/cppunit/_test_asserts.bas
@@ -0,0 +1,66 @@
+'
+' This file is part of the LibreOffice project.
+'
+' This Source Code Form is subject to the terms of the Mozilla Public
+' License, v. 2.0. If a copy of the MPL was not distributed with this
+' file, You can obtain one at http://mozilla.org/MPL/2.0/.
+'
+
+Option Explicit
+
+Dim passCount As Integer
+Dim failCount As Integer
+Dim result As String
+
+Function GetResult()
+ If passCount <> 0 and failCount = 0 Then
+ GetResult = "OK"
+ Else
+ GetResult = result & Chr$(10) & "Tests passed: " & passCount & Chr$(10) & "Tests failed: " & failCount & Chr$(10)
+ End If
+End Function
+
+Sub TestInit()
+ passCount = 0
+ failCount = 0
+ result = result & "Test Results" & Chr$(10) & "============" & Chr$(10)
+End Sub
+
+Sub Assert(Assertion As Boolean, Optional testId As String, Optional testComment As String)
+ If Assertion = True Then
+ passCount = passCount + 1
+ Else
+ Dim testMsg As String
+ If Not IsMissing(testId) Then
+ testMsg = " " + testId
+ End If
+ If Not IsMissing(testComment) And Not (testComment = "") Then
+ testMsg = testMsg + " (" + testComment + ")"
+ End If
+
+ result = result & Chr$(10) & " Failed:" & testMsg
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub AssertEqual(actual As Variant, expected As Variant, testName As String)
+ If expected = actual Then
+ passCount = passCount + 1
+ Else
+ result = result & Chr$(10) & " Failed: " & testName & " returned " & actual & ", expected " & expected
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub AssertEqualApprox(actual, expected, epsilon, testName As String)
+ If Abs(expected - actual) <= epsilon Then
+ passCount = passCount + 1
+ Else
+ result = result & Chr$(10) & " Failed: " & testName & " returned " & actual & ", expected " & expected & ", epsilon " & epsilon
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub ReportErrorHandler(testName As String, aErr, sError, nErl)
+ Assert False, testName, "hit error handler - " & aErr & ": " & sError & " line : " & nErl
+End Sub
diff --git a/basic/qa/cppunit/_test_asserts.vb b/basic/qa/cppunit/_test_asserts.vb
new file mode 100644
index 000000000..0f1d0d886
--- /dev/null
+++ b/basic/qa/cppunit/_test_asserts.vb
@@ -0,0 +1,67 @@
+'
+' This file is part of the LibreOffice project.
+'
+' This Source Code Form is subject to the terms of the Mozilla Public
+' License, v. 2.0. If a copy of the MPL was not distributed with this
+' file, You can obtain one at http://mozilla.org/MPL/2.0/.
+'
+
+Option VBASupport 1
+Option Explicit
+
+Dim passCount As Integer
+Dim failCount As Integer
+Dim result As String
+
+Function GetResult()
+ If passCount <> 0 and failCount = 0 Then
+ GetResult = "OK"
+ Else
+ GetResult = result & Chr$(10) & "Tests passed: " & passCount & Chr$(10) & "Tests failed: " & failCount & Chr$(10)
+ End If
+End Function
+
+Sub TestInit()
+ passCount = 0
+ failCount = 0
+ result = result & "Test Results" & Chr$(10) & "============" & Chr$(10)
+End Sub
+
+Sub Assert(Assertion As Boolean, Optional testId As String, Optional testComment As String)
+ If Assertion = True Then
+ passCount = passCount + 1
+ Else
+ Dim testMsg As String
+ If Not IsMissing(testId) Then
+ testMsg = " " + testId
+ End If
+ If Not IsMissing(testComment) And Not (testComment = "") Then
+ testMsg = testMsg + " (" + testComment + ")"
+ End If
+
+ result = result & Chr$(10) & " Failed:" & testMsg
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub AssertEqual(actual As Variant, expected As Variant, testName As String)
+ If expected = actual Then
+ passCount = passCount + 1
+ Else
+ result = result & Chr$(10) & " Failed: " & testName & " returned " & actual & ", expected " & expected
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub AssertEqualApprox(actual, expected, epsilon, testName As String)
+ If Abs(expected - actual) <= epsilon Then
+ passCount = passCount + 1
+ Else
+ result = result & Chr$(10) & " Failed: " & testName & " returned " & actual & ", expected " & expected & ", epsilon " & epsilon
+ failCount = failCount + 1
+ End If
+End Sub
+
+Sub ReportErrorHandler(testName As String, aErr, sError, nErl)
+ Assert False, testName, "hit error handler - " & aErr & ": " & sError & " line : " & nErl
+End Sub
diff --git a/basic/qa/cppunit/basic_coverage.cxx b/basic/qa/cppunit/basic_coverage.cxx
new file mode 100644
index 000000000..0f0722917
--- /dev/null
+++ b/basic/qa/cppunit/basic_coverage.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "basictest.hxx"
+#include <osl/file.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/syslocaleoptions.hxx>
+
+namespace
+{
+
+class Coverage : public test::BootstrapFixture
+{
+private:
+ void process_directory(const OUString& sDirName);
+ std::vector< OUString > get_subdirnames( const OUString& sDirName );
+
+public:
+ Coverage();
+
+ void Coverage_Iterator();
+
+ // Adds code needed to register the test suite
+ CPPUNIT_TEST_SUITE(Coverage);
+
+ // Declares the method as a test to call
+ CPPUNIT_TEST(Coverage_Iterator);
+
+ // End of test suite definition
+ CPPUNIT_TEST_SUITE_END();
+};
+
+Coverage::Coverage()
+ : BootstrapFixture(true, false)
+{
+}
+
+std::vector< OUString > Coverage::get_subdirnames( const OUString& sDirName )
+{
+ std::vector< OUString > sSubDirNames;
+ osl::Directory aDir(sDirName);
+ osl::DirectoryItem aItem;
+ osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
+
+ if(aDir.open() == osl::FileBase::E_None)
+ {
+ while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
+ {
+ aItem.getFileStatus(aFileStatus);
+ if(aFileStatus.isDirectory())
+ sSubDirNames.push_back( aFileStatus.getFileURL() );
+ }
+ }
+ return sSubDirNames;
+}
+void Coverage::process_directory(const OUString& sDirName)
+{
+ osl::Directory aDir(sDirName);
+ osl::DirectoryItem aItem;
+ osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
+ OUString sMacroUtilsURL = m_directories.getURLFromSrc(u"basic/qa/cppunit/_test_asserts.bas");
+
+ if(aDir.open() == osl::FileBase::E_None)
+ {
+ while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
+ {
+ aItem.getFileStatus(aFileStatus);
+ if(aFileStatus.isRegular())
+ {
+ OUString sFileURL = aFileStatus.getFileURL();
+ if (sFileURL.endsWith(".bas"))
+ {
+ MacroSnippet testMacro;
+ testMacro.LoadSourceFromFile("TestUtil", sMacroUtilsURL);
+ testMacro.LoadSourceFromFile("TestModule", sFileURL);
+ SbxVariableRef pReturn = testMacro.Run();
+ CPPUNIT_ASSERT_MESSAGE("No return variable huh?", pReturn.is());
+ fprintf(stderr, "macro result for %s\n", OUStringToOString(sFileURL,RTL_TEXTENCODING_UTF8).getStr());
+ fprintf(stderr, "macro returned:\n%s\n",
+ OUStringToOString(pReturn->GetOUString(), RTL_TEXTENCODING_UTF8).getStr());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Result not as expected", OUString("OK"),
+ pReturn->GetOUString());
+ }
+ }
+ }
+ }
+ fprintf(stderr,"end process directory\n");
+}
+
+void Coverage::Coverage_Iterator()
+{
+ OUString sDirName = m_directories.getURLFromSrc(u"basic/qa/basic_coverage");
+
+ CPPUNIT_ASSERT(!sDirName.isEmpty());
+ process_directory(sDirName); // any files in the root test dir are run in test harness default locale ( en-US )
+ std::vector< OUString > sLangDirs = get_subdirnames( sDirName );
+
+ for (auto const& langDir : sLangDirs)
+ {
+ sal_Int32 nSlash = langDir.lastIndexOf('/');
+ if ( nSlash != -1 )
+ {
+ OUString sLangISO = langDir.copy( nSlash + 1 );
+ LanguageTag aLocale( sLangISO );
+ if ( aLocale.isValidBcp47() )
+ {
+ SvtSysLocaleOptions aLocalOptions;
+ // set locale for test dir
+ aLocalOptions.SetLocaleConfigString( sLangISO );
+ process_directory(langDir);
+ }
+ }
+ }
+}
+
+ CPPUNIT_TEST_SUITE_REGISTRATION(Coverage);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/basictest.cxx b/basic/qa/cppunit/basictest.cxx
new file mode 100644
index 000000000..8cf9812d5
--- /dev/null
+++ b/basic/qa/cppunit/basictest.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "basictest.hxx"
+#include <cppunit/plugin/TestPlugIn.h>
+#include <basic/sbstar.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbuno.hxx>
+#include <osl/file.hxx>
+
+void MacroSnippet::InitSnippet()
+{
+ mpBasic = new StarBASIC();
+ StarBASIC::SetGlobalErrorHdl( LINK( this, MacroSnippet, BasicErrorHdl ) );
+}
+
+void MacroSnippet::MakeModule(const OUString& sName, const OUString& sSource)
+{
+ mpMod = mpBasic->MakeModule(sName, sSource);
+}
+
+MacroSnippet::MacroSnippet( const OUString& sSource )
+ : mbError(false)
+{
+ InitSnippet();
+ MakeModule("TestModule", sSource);
+}
+
+MacroSnippet::MacroSnippet()
+ : mbError(false)
+{
+ InitSnippet();
+}
+
+void MacroSnippet::LoadSourceFromFile(const OUString& sModuleName, const OUString& sMacroFileURL)
+{
+ OUString sSource;
+ fprintf(stderr,"loadSource opening macro file %s\n", OUStringToOString( sMacroFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ osl::File aFile(sMacroFileURL);
+ if(aFile.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None)
+ {
+ sal_uInt64 size;
+ if(aFile.getSize(size) == osl::FileBase::E_None)
+ {
+ void* buffer = calloc(1, size+1);
+ CPPUNIT_ASSERT(buffer);
+ sal_uInt64 size_read;
+ if(aFile.read( buffer, size, size_read) == osl::FileBase::E_None)
+ {
+ if(size == size_read)
+ {
+ OUString sCode(static_cast<char*>(buffer), size, RTL_TEXTENCODING_UTF8);
+ sSource = sCode;
+ }
+ }
+
+ free(buffer);
+ }
+ }
+ CPPUNIT_ASSERT_MESSAGE( "Source is empty", ( sSource.getLength() > 0 ) );
+ MakeModule(sModuleName, sSource);
+}
+
+SbxVariableRef MacroSnippet::Run( const css::uno::Sequence< css::uno::Any >& rArgs )
+{
+ SbxVariableRef pReturn;
+ if ( !Compile() )
+ return pReturn;
+ SbMethod* pMeth = mpMod.is() ? static_cast<SbMethod*>(mpMod->Find( "doUnitTest", SbxClassType::Method )) : nullptr;
+ if ( pMeth )
+ {
+ if ( rArgs.hasElements() )
+ {
+ SbxArrayRef aArgs = new SbxArray;
+ for ( int i=0; i < rArgs.getLength(); ++i )
+ {
+ SbxVariable* pVar = new SbxVariable();
+ unoToSbxValue( pVar, rArgs[ i ] );
+ aArgs->Put(pVar, i + 1);
+ }
+ pMeth->SetParameters( aArgs.get() );
+ }
+ pReturn = new SbxMethod( *static_cast<SbxMethod*>(pMeth));
+ }
+ return pReturn;
+}
+
+SbxVariableRef MacroSnippet::Run()
+{
+ css::uno::Sequence< css::uno::Any > aArgs;
+ return Run( aArgs );
+}
+
+bool MacroSnippet::Compile()
+{
+ CPPUNIT_ASSERT_MESSAGE("module is NULL", mpMod );
+ mpMod->Compile();
+ return !mbError;
+}
+
+bool MacroSnippet::HasError() const { return mbError; }
+
+const ErrCode& MacroSnippet::getError() const { return maErrCode; }
+
+IMPL_LINK( MacroSnippet, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
+{
+ fprintf(stderr,"(%d:%d)\n",
+ StarBASIC::GetLine(), StarBASIC::GetCol1());
+ fprintf(stderr,"Basic error: %s\n", OUStringToOString( StarBASIC::GetErrorText(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ mbError = true;
+ maErrCode = StarBASIC::GetErrorCode();
+ return false;
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/basictest.hxx b/basic/qa/cppunit/basictest.hxx
new file mode 100644
index 000000000..1901492bc
--- /dev/null
+++ b/basic/qa/cppunit/basictest.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <test/bootstrapfixture.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/basrdll.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbuno.hxx>
+
+class MacroSnippet
+{
+private:
+ bool mbError;
+ ErrCode maErrCode;
+ BasicDLL maDll; // we need a dll instance for resource manager etc.
+ SbModuleRef mpMod;
+ StarBASICRef mpBasic;
+
+ void InitSnippet();
+ void MakeModule(const OUString& sName, const OUString& sSource);
+
+public:
+ explicit MacroSnippet(const OUString& sSource);
+ MacroSnippet();
+
+ void LoadSourceFromFile(const OUString& sName, const OUString& sMacroFileURL);
+
+ SbxVariableRef Run(const css::uno::Sequence<css::uno::Any>& rArgs);
+
+ SbxVariableRef Run();
+
+ bool Compile();
+
+ DECL_LINK(BasicErrorHdl, StarBASIC*, bool);
+
+ bool HasError() const;
+ const ErrCode& getError() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/test_append.cxx b/basic/qa/cppunit/test_append.cxx
new file mode 100644
index 000000000..aa3280a4a
--- /dev/null
+++ b/basic/qa/cppunit/test_append.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "basictest.hxx"
+
+namespace
+{
+ class EnableTest : public test::BootstrapFixture
+ {
+ public:
+ EnableTest() : BootstrapFixture(true, false) {};
+ void testDimEnable();
+ void testWin64();
+ void testEnableRuntime();
+ // Adds code needed to register the test suite
+ CPPUNIT_TEST_SUITE(EnableTest);
+
+ // Declares the method as a test to call
+ CPPUNIT_TEST(testDimEnable);
+ CPPUNIT_TEST(testWin64);
+ CPPUNIT_TEST(testEnableRuntime);
+
+ // End of test suite definition
+ CPPUNIT_TEST_SUITE_END();
+ };
+
+OUString sTestEnableRuntime(
+ "Function doUnitTest as Integer\n"
+ "Dim Enable as Integer\n"
+ "Enable = 1\n"
+ "Enable = Enable + 2\n"
+ "doUnitTest = Enable\n"
+ "End Function\n"
+);
+
+OUString sTestDimEnable(
+ "Sub doUnitTest\n"
+ "Dim Enable as String\n"
+ "End Sub\n"
+);
+
+void EnableTest::testEnableRuntime()
+{
+ MacroSnippet myMacro(sTestEnableRuntime);
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testEnableRuntime fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(3), pNew->GetInteger());
+}
+
+void EnableTest::testDimEnable()
+{
+ MacroSnippet myMacro(sTestDimEnable);
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("Dim causes compile error", !myMacro.HasError() );
+}
+
+void EnableTest::testWin64()
+{
+ MacroSnippet myMacro(" #If Win64\n"
+ "Declare PtrSafe Function aht_apiGetOpenFileName Lib \"comdlg32.dll\""
+ "\n"
+ "#End if\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("#if Win64 Declare PtrSafe causes compile error", !myMacro.HasError() );
+}
+
+ // Put the test suite in the registry
+ CPPUNIT_TEST_SUITE_REGISTRATION(EnableTest);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/test_compiler_checks.cxx b/basic/qa/cppunit/test_compiler_checks.cxx
new file mode 100644
index 000000000..044977670
--- /dev/null
+++ b/basic/qa/cppunit/test_compiler_checks.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+#include "basictest.hxx"
+#include <basic/sberrors.hxx>
+#include <unotest/bootstrapfixturebase.hxx>
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testRedefineArgument)
+{
+ MacroSnippet aMacro("Sub doUnitTest(argName)\n"
+ " If False Then\n"
+ " Dim argName\n"
+ " End If\n"
+ "End Sub\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(aMacro.HasError());
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_BASIC_VAR_DEFINED, aMacro.getError().StripDynamic());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testDoubleArgument)
+{
+ MacroSnippet aMacro("Sub doUnitTest(argName, argName)\n"
+ "End Sub\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(aMacro.HasError());
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_BASIC_VAR_DEFINED, aMacro.getError().StripDynamic());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149157)
+{
+ MacroSnippet aMacro("Function extentComment() As Integer\n"
+ " ' _\n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149157_compatible)
+{
+ MacroSnippet aMacro("Option Compatible\n"
+ "Function extentComment() As Integer\n"
+ " ' _\n"
+ "\n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149157_vba)
+{
+ MacroSnippet aMacro("Option VBASupport 1\n"
+ "Function extentComment() As Integer\n"
+ " ' _\n"
+ "\n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149402)
+{
+ MacroSnippet aMacro("Function extentComment() As Integer\n"
+ " ' _ \n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " Else\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149402_compatible)
+{
+ MacroSnippet aMacro("Option Compatible\n"
+ "Function extentComment() As Integer\n"
+ " ' _ \n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " Else\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149402_vba)
+{
+ MacroSnippet aMacro("Option VBASupport 1\n"
+ "Function extentComment() As Integer\n"
+ " ' _ \n"
+ " If Not extentComment Then\n"
+ " extentComment = 1\n"
+ " Else\n"
+ " End If\n"
+ "End Function\n");
+ aMacro.Compile();
+ CPPUNIT_ASSERT(!aMacro.HasError());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/basic/qa/cppunit/test_global_array.cxx b/basic/qa/cppunit/test_global_array.cxx
new file mode 100644
index 000000000..5317e8701
--- /dev/null
+++ b/basic/qa/cppunit/test_global_array.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <basic/sbstar.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/basrdll.hxx>
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace
+{
+class GlobalArrayTest : public CppUnit::TestFixture
+{
+ void testMaintainsValueAcrossCalls();
+
+ CPPUNIT_TEST_SUITE(GlobalArrayTest);
+ CPPUNIT_TEST(testMaintainsValueAcrossCalls);
+ CPPUNIT_TEST_SUITE_END();
+
+ BasicDLL lib;
+ StarBASICRef interpreter;
+
+ SbModuleRef Module()
+ {
+ interpreter = new StarBASIC();
+ auto mod = interpreter->MakeModule("GlobalArray", R"BAS(
+
+Type testType
+ iNr As Integer
+ sType As String
+End Type
+
+Global aTestTypes(2) As New testType
+
+Function Macro1 As String
+ aTestTypes(0).iNr = 1
+ aTestTypes(0).sType = "A"
+ Macro1 = aTestTypes(0).iNr & aTestTypes(0).sType
+End Function
+
+Function Macro2 As String
+ aTestTypes(1).iNr = 2
+ aTestTypes(1).sType = "B"
+ Macro2 = aTestTypes(0).iNr & aTestTypes(0).sType & aTestTypes(1).iNr & aTestTypes(1).sType
+End Function
+
+ )BAS");
+ CPPUNIT_ASSERT(mod->Compile());
+ CPPUNIT_ASSERT_EQUAL(StarBASIC::GetErrBasic(), ERRCODE_NONE);
+ CPPUNIT_ASSERT_EQUAL(SbxBase::GetError(), ERRCODE_NONE);
+ CPPUNIT_ASSERT(mod->IsCompiled());
+ return mod;
+ }
+};
+
+void GlobalArrayTest::testMaintainsValueAcrossCalls()
+{
+ auto m = Module();
+ auto Macro1 = m->FindMethod("Macro1", SbxClassType::Method);
+ CPPUNIT_ASSERT_MESSAGE("Could not Find Macro1 in module", Macro1 != nullptr);
+
+ // There is no SbxMethod::call(), the basic code is exercised here in the copy ctor
+ SbxVariableRef returned = new SbxMethod{ *Macro1 };
+ CPPUNIT_ASSERT(returned->IsString());
+ CPPUNIT_ASSERT_EQUAL(OUString{ "1A" }, returned->GetOUString());
+
+ auto Macro2 = m->FindMethod("Macro2", SbxClassType::Method);
+ CPPUNIT_ASSERT_MESSAGE("Could not Find Macro2 in module", Macro2 != nullptr);
+ returned = new SbxMethod{ *Macro2 };
+ CPPUNIT_ASSERT(returned->IsString());
+ // tdf#145371 - check if the global array has maintained its state
+ // Without the fix in place, this test would have failed with:
+ // - Expected: 1A2B
+ // - Actual : 02B
+ CPPUNIT_ASSERT_EQUAL(OUString("1A2B"), returned->GetOUString());
+}
+
+// Put the test suite in the registry
+CPPUNIT_TEST_SUITE_REGISTRATION(GlobalArrayTest);
+
+} // namespace
diff --git a/basic/qa/cppunit/test_global_as_new.cxx b/basic/qa/cppunit/test_global_as_new.cxx
new file mode 100644
index 000000000..ea5b6fcc5
--- /dev/null
+++ b/basic/qa/cppunit/test_global_as_new.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <basic/sbstar.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/basrdll.hxx>
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace
+{
+class GlobalAsNewTest : public CppUnit::TestFixture
+{
+ void testMaintainsValueAcrossCalls();
+
+ CPPUNIT_TEST_SUITE(GlobalAsNewTest);
+ CPPUNIT_TEST(testMaintainsValueAcrossCalls);
+ CPPUNIT_TEST_SUITE_END();
+
+ BasicDLL lib;
+ StarBASICRef interpreter;
+
+ SbModuleRef Module()
+ {
+ interpreter = new StarBASIC();
+ auto mod = interpreter->MakeModule("GlobalAsNew", R"BAS(
+Global aDate As New "com.sun.star.util.Date"
+
+Function GetDateAsString As String
+ DIM local_Date As New "com.sun.star.util.Date"
+ GetDateAsString = TRIM(STR(aDate.Year)) + "-" + TRIM(STR(local_Date.Year)) + TRIM(STR(aDate.Month)) + "-" + TRIM(STR(aDate.Day))
+End Function
+
+Function SetDate
+ aDate.Month = 6
+ aDate.Day = 30
+ aDate.Year = 2019
+ SetDate = GetDateAsString()
+End Function
+
+ )BAS");
+ CPPUNIT_ASSERT(mod->Compile());
+ CPPUNIT_ASSERT_EQUAL(StarBASIC::GetErrBasic(), ERRCODE_NONE);
+ CPPUNIT_ASSERT_EQUAL(SbxBase::GetError(), ERRCODE_NONE);
+ CPPUNIT_ASSERT(mod->IsCompiled());
+ return mod;
+ }
+};
+
+void GlobalAsNewTest::testMaintainsValueAcrossCalls()
+{
+ auto m = Module();
+ auto GetDateAsString = m->FindMethod("GetDateAsString", SbxClassType::Method);
+ CPPUNIT_ASSERT_MESSAGE("Could not Find GetDateAsString in module", GetDateAsString != nullptr);
+
+ // There is no SbxMethod::call(), the basic code is exercised here in the copy ctor
+ SbxVariableRef returned = new SbxMethod{ *GetDateAsString };
+ CPPUNIT_ASSERT(returned->IsString());
+ //0-00-0 is the result of reading the default-initialized date
+ CPPUNIT_ASSERT_EQUAL(OUString{ "0-00-0" }, returned->GetOUString());
+
+ auto SetDate = m->FindMethod("SetDate", SbxClassType::Method);
+ CPPUNIT_ASSERT_MESSAGE("Could not Find SetDate in module", SetDate != nullptr);
+ returned = new SbxMethod{ *SetDate };
+ CPPUNIT_ASSERT(returned->IsString());
+ OUString set_val("2019-06-30");
+ CPPUNIT_ASSERT_EQUAL(set_val, returned->GetOUString());
+
+ returned = new SbxMethod{ *GetDateAsString };
+ CPPUNIT_ASSERT(returned->IsString());
+ //tdf#88442 The global should have maintained its state!
+ CPPUNIT_ASSERT_EQUAL(set_val, returned->GetOUString());
+}
+
+// Put the test suite in the registry
+CPPUNIT_TEST_SUITE_REGISTRATION(GlobalAsNewTest);
+
+} // namespace
diff --git a/basic/qa/cppunit/test_language_conditionals.cxx b/basic/qa/cppunit/test_language_conditionals.cxx
new file mode 100644
index 000000000..c35d5571e
--- /dev/null
+++ b/basic/qa/cppunit/test_language_conditionals.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "basictest.hxx"
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace
+{
+class Language_Conditionals : public CppUnit::TestFixture
+{
+public:
+ void testIfNot();
+ void testIfAndNot();
+ void testNENot();
+
+ CPPUNIT_TEST_SUITE(Language_Conditionals);
+
+ CPPUNIT_TEST(testIfNot);
+ CPPUNIT_TEST(testIfAndNot);
+ CPPUNIT_TEST(testNENot);
+
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void Language_Conditionals::testIfNot()
+{
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 1\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "op1 = False\n"
+ "If Not op1 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 0\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "op1 = False\n"
+ "If Not op1 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+}
+
+void Language_Conditionals::testIfAndNot()
+{
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 1\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "Dim op2 As Boolean\n"
+ "op1 = True\n"
+ "op2 = False\n"
+ "If op1 And Not op2 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 0\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "Dim op2 As Boolean\n"
+ "op1 = True\n"
+ "op2 = False\n"
+ "If op1 And Not op2 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+}
+
+void Language_Conditionals::testNENot()
+{
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 1\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "Dim op2 As Boolean\n"
+ "op1 = False\n"
+ "op2 = False\n"
+ "If op1 <> Not op2 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+ { // need a block to ensure MacroSnippet is cleaned properly
+ MacroSnippet myMacro("Option VBASupport 0\n"
+ "Option Explicit\n"
+ "\n"
+ "Function doUnitTest() As Integer\n"
+ "Dim op1 As Boolean\n"
+ "Dim op2 As Boolean\n"
+ "op1 = False\n"
+ "op2 = False\n"
+ "If op1 <> Not op2 Then\n"
+ "doUnitTest = 1\n"
+ "Else\n"
+ "doUnitTest = 0\n"
+ "End If\n"
+ "End Function\n");
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Language_Conditionals);
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/basic/qa/cppunit/test_nested_struct.cxx b/basic/qa/cppunit/test_nested_struct.cxx
new file mode 100644
index 000000000..daced48ba
--- /dev/null
+++ b/basic/qa/cppunit/test_nested_struct.cxx
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "basictest.hxx"
+
+#include <com/sun/star/awt/WindowDescriptor.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <basic/sbuno.hxx>
+
+namespace
+{
+ using namespace com::sun::star;
+ class Nested_Struct : public test::BootstrapFixture
+ {
+ public:
+ Nested_Struct(): BootstrapFixture(true, false) {};
+ void testAssign1();
+ void testAssign1Alt(); // result is uno-ised and tested
+ void testOldAssign();
+ void testOldAssignAlt(); // result is uno-ised and tested
+ void testUnfixedVarAssign();
+ void testUnfixedVarAssignAlt(); // result is uno-ised and tested
+ void testFixedVarAssign();
+ void testFixedVarAssignAlt(); // result is uno-ised and tested
+ void testUnoAccess(); // fdo#60117 specific test
+ void testTdf134576();
+
+ // Adds code needed to register the test suite
+ CPPUNIT_TEST_SUITE(Nested_Struct);
+
+ // Declares the method as a test to call
+ CPPUNIT_TEST(testAssign1);
+ CPPUNIT_TEST(testAssign1Alt);
+ CPPUNIT_TEST(testOldAssign);
+ CPPUNIT_TEST(testOldAssignAlt);
+ CPPUNIT_TEST(testUnfixedVarAssign);
+ CPPUNIT_TEST(testUnfixedVarAssignAlt);
+ CPPUNIT_TEST(testFixedVarAssign);
+ CPPUNIT_TEST(testFixedVarAssignAlt);
+ CPPUNIT_TEST(testUnoAccess);
+ CPPUNIT_TEST(testTdf134576);
+
+ // End of test suite definition
+ CPPUNIT_TEST_SUITE_END();
+ };
+
+// tests the new behaviour, we should be able to
+// directly modify the value of the nested 'HorizontalLine' struct
+OUString sTestSource1(
+ "Function doUnitTest() as Integer\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\"\n"
+ "b0.HorizontalLine.OuterLineWidth = 9\n"
+ "doUnitTest = b0.HorizontalLine.OuterLineWidth\n"
+ "End Function\n"
+);
+
+OUString sTestSource1Alt(
+ "Function doUnitTest() as Object\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\"\n"
+ "b0.HorizontalLine.OuterLineWidth = 9\n"
+ "doUnitTest = b0\n"
+ "End Function\n"
+);
+
+// tests the old behaviour, we should still be able
+// to use the old workaround of
+// a) creating a new instance BorderLine,
+// b) cloning the new instance with the value of b0.HorizontalLine
+// c) modifying the new instance
+// d) setting b0.HorizontalLine with the value of the new instance
+OUString sTestSource2(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\", l as new \"com.sun.star.table.BorderLine\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "doUnitTest = b0.HorizontalLine.OuterLineWidth\n"
+"End Function\n"
+);
+
+OUString sTestSource2Alt(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\", l as new \"com.sun.star.table.BorderLine\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "doUnitTest = b0\n"
+"End Function\n"
+);
+// it should be legal to assign a variant to a struct ( and copy by val )
+// make sure we aren't copying by reference, we make sure that l is not
+// a reference copy of b0.HorizontalLine, each one should have an
+// OuterLineWidth of 4 & 9 respectively and we should be returning
+// 13 the sum of the two ( hopefully unique values if we haven't copied by reference )
+OUString sTestSource3(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "l.OuterLineWidth = 4\n"
+ "doUnitTest = b0.HorizontalLine.OuterLineWidth + l.OuterLineWidth\n"
+"End Function\n"
+);
+
+OUString sTestSource3Alt(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "l.OuterLineWidth = 4\n"
+ "Dim result(1)\n"
+ "result(0) = b0\n"
+ "result(1) = l\n"
+ "doUnitTest = result\n"
+"End Function\n"
+);
+
+// nearly the same as above but this time for a fixed type
+// variable
+OUString sTestSource4(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\", l as new \"com.sun.star.table.BorderLine\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "l.OuterLineWidth = 4\n"
+ "doUnitTest = b0.HorizontalLine.OuterLineWidth + l.OuterLineWidth\n"
+"End Function\n"
+);
+
+OUString sTestSource4Alt(
+ "Function doUnitTest()\n"
+ "Dim b0 as new \"com.sun.star.table.TableBorder\", l as new \"com.sun.star.table.BorderLine\"\n"
+ "l = b0.HorizontalLine\n"
+ "l.OuterLineWidth = 9\n"
+ "b0.HorizontalLine = l\n"
+ "l.OuterLineWidth = 4\n"
+ "Dim result(1)\n"
+ "result(0) = b0\n"
+ "result(1) = l\n"
+ "doUnitTest = result\n"
+"End Function\n"
+);
+
+// Although basic might appear to correctly change nested struct elements
+// fdo#60117 shows that basic can be fooled ( and even the watch(ed) variable
+// in the debugger shows the expected values )
+// We need to additionally check the actual uno struct to see if the
+// changes made are *really* reflected in the object
+OUString sTestSource5(
+ "Function doUnitTest() as Object\n"
+ "Dim aWinDesc as new \"com.sun.star.awt.WindowDescriptor\"\n"
+ "Dim aRect as new \"com.sun.star.awt.Rectangle\"\n"
+ "aRect.X = 200\n"
+ "aWinDesc.Bounds = aRect\n"
+ "doUnitTest = aWinDesc\n"
+"End Function\n"
+);
+
+
+void Nested_Struct::testAssign1()
+{
+ MacroSnippet myMacro( sTestSource1 );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testAssign1 fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(9), pNew->GetInteger());
+}
+
+void Nested_Struct::testAssign1Alt()
+{
+ MacroSnippet myMacro( sTestSource1Alt );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testAssign1Alt fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ uno::Any aRet = sbxToUnoValue( pNew.get() );
+ table::TableBorder aBorder;
+ aRet >>= aBorder;
+
+ int result = aBorder.HorizontalLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL( 9, result );
+}
+
+void Nested_Struct::testOldAssign()
+{
+ MacroSnippet myMacro( sTestSource2 );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testOldAssign fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(9), pNew->GetInteger());
+}
+
+void Nested_Struct::testOldAssignAlt()
+{
+ MacroSnippet myMacro( sTestSource2Alt );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testOldAssign fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ uno::Any aRet = sbxToUnoValue( pNew.get() );
+ table::TableBorder aBorder;
+ aRet >>= aBorder;
+
+ int result = aBorder.HorizontalLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL( 9, result );
+}
+
+void Nested_Struct::testUnfixedVarAssign()
+{
+ MacroSnippet myMacro( sTestSource3 );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testUnfixedVarAssign fails with compile error",!myMacro.HasError() );
+ // forces a broadcast
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(13), pNew->GetInteger());
+}
+
+void Nested_Struct::testUnfixedVarAssignAlt()
+{
+ MacroSnippet myMacro( sTestSource3Alt );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testUnfixedVarAssignAlt fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ uno::Any aRet = sbxToUnoValue( pNew.get() );
+
+ uno::Sequence< uno::Any > aResult;
+ bool bRes = aRet >>= aResult;
+ CPPUNIT_ASSERT_EQUAL(true, bRes );
+
+ int result = aResult.getLength();
+ // should have 2 elements in a sequence returned
+ CPPUNIT_ASSERT_EQUAL(2, result );
+
+ table::TableBorder aBorder;
+ aResult[0] >>= aBorder;
+
+ table::BorderLine aBorderLine;
+ aResult[1] >>= aBorderLine;
+ result = aBorder.HorizontalLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL(9, result );
+ result = aBorderLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL(4, result );
+}
+
+void Nested_Struct::testFixedVarAssign()
+{
+ MacroSnippet myMacro( sTestSource4 );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testFixedVarAssign fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(13), pNew->GetInteger());
+}
+
+void Nested_Struct::testFixedVarAssignAlt()
+{
+ MacroSnippet myMacro( sTestSource4Alt );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testFixedVarAssignAlt fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ uno::Any aRet = sbxToUnoValue( pNew.get() );
+
+ uno::Sequence< uno::Any > aResult;
+ bool bRes = aRet >>= aResult;
+ CPPUNIT_ASSERT_EQUAL(true, bRes );
+
+ int result = aResult.getLength();
+ // should have 2 elements in a sequence returned
+ CPPUNIT_ASSERT_EQUAL(2, result );
+
+ table::TableBorder aBorder;
+ aResult[0] >>= aBorder;
+
+ table::BorderLine aBorderLine;
+ aResult[1] >>= aBorderLine;
+ result = aBorder.HorizontalLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL(9, result );
+ result = aBorderLine.OuterLineWidth;
+ CPPUNIT_ASSERT_EQUAL(4, result );
+}
+
+void Nested_Struct::testUnoAccess()
+{
+ MacroSnippet myMacro( sTestSource5 );
+ myMacro.Compile();
+ CPPUNIT_ASSERT_MESSAGE("testUnoAccess fails with compile error",!myMacro.HasError() );
+ SbxVariableRef pNew = myMacro.Run();
+ uno::Any aRet = sbxToUnoValue( pNew.get() );
+ awt::WindowDescriptor aWinDesc;
+ aRet >>= aWinDesc;
+
+ int result = aWinDesc.Bounds.X;
+ CPPUNIT_ASSERT_EQUAL(200, result );
+}
+
+void Nested_Struct::testTdf134576()
+{
+ MacroSnippet myMacro("Function doUnitTest()\n"
+ " On Error Resume Next\n"
+ " For Each a In b\n"
+ " c.d\n"
+ " Next\n"
+ " doUnitTest = 1\n"
+ "End Function\n");
+
+ myMacro.Compile();
+ CPPUNIT_ASSERT(!myMacro.HasError());
+
+ // Without the fix in place, it would have crashed here
+ SbxVariableRef pNew = myMacro.Run();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), pNew->GetInteger());
+}
+
+ // Put the test suite in the registry
+ CPPUNIT_TEST_SUITE_REGISTRATION(Nested_Struct);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/test_scanner.cxx b/basic/qa/cppunit/test_scanner.cxx
new file mode 100644
index 000000000..6559b3e35
--- /dev/null
+++ b/basic/qa/cppunit/test_scanner.cxx
@@ -0,0 +1,1165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/types.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <limits>
+
+#include <scanner.hxx>
+
+namespace
+{
+struct Symbol
+{
+ sal_uInt16 line;
+ sal_uInt16 col1;
+ OUString text;
+ double number;
+ SbxDataType type;
+ bool ws;
+};
+
+/**
+ * Perform tests on Scanner.
+ */
+class ScannerTest : public CppUnit::TestFixture
+{
+private:
+ void testBlankLines();
+ void testOperators();
+ void testAlphanum();
+ void testComments();
+ void testGoto();
+ void testGotoCompatible();
+ void testExclamation();
+ void testNumbers();
+ void testDataType();
+ void testHexOctal();
+ void testTdf103104();
+ void testTdf136032();
+
+ // Adds code needed to register the test suite
+ CPPUNIT_TEST_SUITE(ScannerTest);
+
+ // Declares the method as a test to call
+ CPPUNIT_TEST(testBlankLines);
+ CPPUNIT_TEST(testOperators);
+ CPPUNIT_TEST(testAlphanum);
+ CPPUNIT_TEST(testComments);
+ CPPUNIT_TEST(testGoto);
+ CPPUNIT_TEST(testGotoCompatible);
+ CPPUNIT_TEST(testExclamation);
+ CPPUNIT_TEST(testNumbers);
+ CPPUNIT_TEST(testDataType);
+ CPPUNIT_TEST(testHexOctal);
+ CPPUNIT_TEST(testTdf103104);
+ CPPUNIT_TEST(testTdf136032);
+
+ // End of test suite definition
+ CPPUNIT_TEST_SUITE_END();
+};
+
+const OUString cr = "\n";
+const OUString rem = "REM";
+const OUString asdf = "asdf";
+const OUString dot = ".";
+const OUString goto_ = "goto";
+const OUString excl = "!";
+
+std::vector<Symbol> getSymbols(const OUString& source, sal_Int32& errors, bool bCompatible = false)
+{
+ std::vector<Symbol> symbols;
+ SbiScanner scanner(source);
+ scanner.EnableErrors();
+ scanner.SetCompatible(bCompatible);
+ while (scanner.NextSym())
+ {
+ Symbol symbol;
+ symbol.line = scanner.GetLine();
+ symbol.col1 = scanner.GetCol1();
+ symbol.text = scanner.GetSym();
+ symbol.number = scanner.GetDbl();
+ symbol.type = scanner.GetType();
+ symbol.ws = scanner.WhiteSpace();
+ symbols.push_back(symbol);
+ }
+ errors = scanner.GetErrors();
+ return symbols;
+}
+
+std::vector<Symbol> getSymbols(const OUString& source, bool bCompatible = false)
+{
+ sal_Int32 i;
+ return getSymbols(source, i, bCompatible);
+}
+
+void ScannerTest::testBlankLines()
+{
+ std::vector<Symbol> symbols;
+ symbols = getSymbols("");
+ CPPUNIT_ASSERT(symbols.empty());
+
+ symbols = getSymbols("\r\n");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+
+ symbols = getSymbols("\n");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+
+ symbols = getSymbols("\r");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+
+ symbols = getSymbols("\r\n\r\n");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("\n\r");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("\n\r\n");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("\r\n\r");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(" ");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+}
+
+void ScannerTest::testOperators()
+{
+ const OUString sourceE("=");
+ const OUString sourceLT("<");
+ const OUString sourceGT(">");
+ const OUString sourceLTE("<=");
+ const OUString sourceGTE(">=");
+ const OUString sourceNE("<>");
+ const OUString sourceA(":=");
+ const OUString sourceNot("Not");
+
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols(sourceE);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceE, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceLT);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceLT, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceGT);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceGT, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceLTE);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceLTE, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceGTE);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceGTE, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("==");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceE, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(sourceE, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+
+ symbols = getSymbols(sourceNE);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceNE, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceA);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceA, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(sourceNot);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(sourceNot, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+}
+
+void ScannerTest::testAlphanum()
+{
+ const OUString source1("asdfghefg");
+ const OUString source3("AdfsaAUdsl10987");
+ const OUString source4("asdfa_mnvcnm");
+ const OUString source5("_asdf1");
+ const OUString source6("_6");
+ const OUString source7("joxclk_");
+
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols(source1);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(source1, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("1asfdasfd");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT(symbols[0].text.isEmpty()); // Can't start symbol with a digit
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("asfdasfd"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+
+ symbols = getSymbols(source3);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(source3, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(source4);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(source4, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(source5);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(source5, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(source6);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(source6, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(source7);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("joxclk_"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ // tdf#125637 - don't change underscore to space
+ CPPUNIT_ASSERT_EQUAL(OUString("joxclk_"), source7);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(" asdf ");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("asdf"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols(" 19395 asdfa ");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT(symbols[0].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(19395.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("asdfa"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+
+ symbols = getSymbols("\n1\n2\na sdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(8), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT(symbols[1].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+ CPPUNIT_ASSERT(symbols[3].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, symbols[3].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[3].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[4].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[4].type);
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(symbols[5].text.getLength()));
+ CPPUNIT_ASSERT_EQUAL('a', static_cast<char>(symbols[5].text[0]));
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[5].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("sdf"), symbols[6].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[6].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[7].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[7].type);
+
+ symbols = getSymbols("asdf.asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(dot, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[3].type);
+
+ symbols = getSymbols("..");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(dot, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(dot, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+}
+
+void ScannerTest::testComments()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("REM asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+
+ symbols = getSymbols("REMasdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("REMasdf"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("'asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(1), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+
+ symbols = getSymbols("asdf _\n'100");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("'asdf _\n100");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT(symbols[1].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(100.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+
+ symbols = getSymbols("'asdf _\n'100");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("'asdf _\n 1234 _\n asdf'");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT(symbols[1].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1234.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+ CPPUNIT_ASSERT_EQUAL(rem, symbols[3].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[3].type);
+}
+
+void ScannerTest::testGoto()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("goto");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(goto_, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+
+ symbols = getSymbols("go to");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("go"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("to"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+
+ symbols = getSymbols("go\nto");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("go"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("to"), symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[2].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[3].type);
+}
+
+void ScannerTest::testGotoCompatible()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("goto", true);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(goto_, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("go to", true);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(goto_, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("go\nto", true);
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("go"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("to"), symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+}
+
+void ScannerTest::testExclamation()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("asdf!asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+
+ symbols = getSymbols("!1234");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[0].text);
+ CPPUNIT_ASSERT(symbols[1].text.isEmpty());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1234.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("!_3");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("_3"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("!$");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("$"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("!%");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("%"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("!\n");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(excl, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+}
+
+void ScannerTest::testNumbers()
+{
+ std::vector<Symbol> symbols;
+ sal_Int32 errors;
+
+ symbols = getSymbols("12345", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(12345.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("1.2.3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.2, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(.3, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("123.4", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(123.4, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("0.5", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(.5, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("5.0", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("0.0", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("-3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("-"), symbols[0].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("-0.0", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("-"), symbols[0].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12dE3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(12.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("dE3"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12e3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(12000.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12D+3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(12000.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12e++3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(6), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(12.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("e"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("+"), symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(OUString("+"), symbols[3].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, symbols[4].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[4].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[5].text);
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12e-3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(.012, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("12e-3+", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(.012, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString("+"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("1,2,3", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(6), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(OUString(","), symbols[1].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, symbols[2].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[2].type);
+ CPPUNIT_ASSERT_EQUAL(OUString(","), symbols[3].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, symbols[4].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[4].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[5].text);
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+
+ symbols = getSymbols("1."
+ "0000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000",
+ errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // This error is from a "buffer overflow" which is stupid because
+ // the buffer is artificially constrained by the scanner.
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors)); // HACK
+
+ symbols = getSymbols("10e308", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(std::numeric_limits<double>::infinity(), symbols[0].number);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors)); // math error, overflow
+
+ // trailing data type character % = SbxINTEGER
+ symbols = getSymbols("1.23%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // trailing data type character & = SbxLONG
+ symbols = getSymbols("1.23&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // trailing data type character ! = SbxSINGLE
+ symbols = getSymbols("1.23!");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // trailing data type character # = SbxDOUBLE
+ symbols = getSymbols("1.23#");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // trailing data type character @ = SbxCURRENCY
+ symbols = getSymbols("1.23@");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // trailing data type character $ = SbxSTRING
+ symbols = getSymbols("1.23$", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_SYNTAX
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+}
+
+void ScannerTest::testDataType()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("asdf%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf!");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf#");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf@");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf$");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("asdf ");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+}
+
+void ScannerTest::testHexOctal()
+{
+ sal_Int32 errors;
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("&HA");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(10.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&HASDF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2783.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&H10");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(16.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&&H&1H1&H1");
+ CPPUNIT_ASSERT_EQUAL(size_t(6), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString("&"), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[1].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[2].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[2].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[2].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[3].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString("H1"), symbols[3].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[3].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[4].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString("H1"), symbols[4].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[4].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[5].text);
+
+ symbols = getSymbols("&O&O12");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString("O12"), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("&O10");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(8.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&HO");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&O123000000000000000000000");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ // TODO: this line fails on 64 bit systems!!!
+ // CPPUNIT_ASSERT_EQUAL(symbols[0].number, -1744830464);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&H1.23");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(.23, symbols[1].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[1].text);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[1].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ /* tdf#62323, tdf#62326 - conversion of Hex literals to basic signed Integers */
+
+ // &H0 = 0
+ symbols = getSymbols("&H0");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &H8000 = -32768
+ symbols = getSymbols("&H8000");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(SbxMININT, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &H80000000 = -2147483648
+ symbols = getSymbols("&H80000000");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(SbxMINLNG, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &HFFFF = -1
+ symbols = getSymbols("&HFFFF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &HFFFFFFFF = -1
+ symbols = getSymbols("&HFFFFFFFF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &H7FFF = 32767
+ symbols = getSymbols("&H7FFF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(SbxMAXINT, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &H7FFFFFFF = 2147483647
+ symbols = getSymbols("&H7FFFFFFF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(SbxMAXLNG, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ /* tdf#130476 - trailing data type characters */
+
+ // % = SbxINTEGER
+ symbols = getSymbols("&H0%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // & = SbxLONG
+ symbols = getSymbols("&H0&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // ! = SbxSINGLE
+ symbols = getSymbols("&H0!");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // # = SbxDOUBLE
+ symbols = getSymbols("&H0#");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // @ = SbxCURRENCY
+ symbols = getSymbols("&H0@");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // $ = SbxSTRING
+ symbols = getSymbols("&H0$", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_SYNTAX
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ // % = SbxINTEGER
+ symbols = getSymbols("&O0%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // & = SbxLONG
+ symbols = getSymbols("&O0&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // ! = SbxSINGLE
+ symbols = getSymbols("&O0!");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // # = SbxDOUBLE
+ symbols = getSymbols("&O0#");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // @ = SbxCURRENCY
+ symbols = getSymbols("&O0@");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // $ = SbxSTRING
+ symbols = getSymbols("&O0$", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_SYNTAX
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ // maximum for Hex % = SbxINTEGER
+ symbols = getSymbols("&HFFFF%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // overflow for Hex % = SbxINTEGER
+ symbols = getSymbols("&H10000%", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_MATH_OVERFLOW
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ // maximum for Octal % = SbxINTEGER
+ symbols = getSymbols("&O177777%");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // overflow for Octal % = SbxINTEGER
+ symbols = getSymbols("&O200000%", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_MATH_OVERFLOW
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ // maximum for Hex & = SbxLONG
+ symbols = getSymbols("&H7FFFFFFF&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2147483647.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // minimum for Hex & = SbxLONG
+ symbols = getSymbols("&H80000000&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-2147483648.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // overflow for Hex & = SbxLONG
+ symbols = getSymbols("&H100000000&", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_MATH_OVERFLOW
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ // maximum for Octal & = SbxLONG
+ symbols = getSymbols("&O17777777777&");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2147483647.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // minimum for Octal & = SbxLONG
+ symbols = getSymbols("&O20000000000&", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-2147483648.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // overflow for Octal & = SbxLONG
+ symbols = getSymbols("&O40000000000&", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+ // ERRCODE_BASIC_MATH_OVERFLOW
+ CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
+
+ /* test for leading zeros */
+
+ // &H0000000FFFF = 65535
+ symbols = getSymbols("&H0000000FFFF");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ // &O00000123 = 83
+ symbols = getSymbols("&O00000123");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(83.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+
+ symbols = getSymbols("&O7777777");
+ CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(2097151.0, symbols[0].number, 1E-12);
+ CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
+}
+
+void ScannerTest::testTdf103104()
+{
+ std::vector<Symbol> symbols;
+
+ symbols = getSymbols("asdf _\n asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[1].text);
+ CPPUNIT_ASSERT(symbols[1].ws);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[2].text);
+
+ symbols = getSymbols("asdf. _\n asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(dot, symbols[1].text);
+ CPPUNIT_ASSERT(!symbols[1].ws);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[2].text);
+ CPPUNIT_ASSERT(symbols[2].ws);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+
+ symbols = getSymbols("asdf _\n .asdf");
+ CPPUNIT_ASSERT_EQUAL(size_t(4), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[0].text);
+ CPPUNIT_ASSERT_EQUAL(dot, symbols[1].text);
+ CPPUNIT_ASSERT(!symbols[1].ws);
+ CPPUNIT_ASSERT_EQUAL(asdf, symbols[2].text);
+ CPPUNIT_ASSERT(!symbols[2].ws);
+ CPPUNIT_ASSERT_EQUAL(cr, symbols[3].text);
+}
+
+void ScannerTest::testTdf136032()
+{
+ std::vector<Symbol> symbols;
+ sal_Int32 errors;
+
+ // tdf#136032 - abort scan of a string beginning with a hashtag,
+ // if a comma/whitespace is found. Otherwise, the compiler raises a syntax error.
+ symbols = getSymbols("Print #i,\"A#B\"", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(5), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+ symbols = getSymbols("Print #i, \"A#B\"", errors);
+ CPPUNIT_ASSERT_EQUAL(size_t(5), symbols.size());
+ CPPUNIT_ASSERT_EQUAL(0u, static_cast<unsigned int>(errors));
+}
+
+// Put the test suite in the registry
+CPPUNIT_TEST_SUITE_REGISTRATION(ScannerTest);
+} // namespace
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/qa/cppunit/test_vba.cxx b/basic/qa/cppunit/test_vba.cxx
new file mode 100644
index 000000000..f048fee6d
--- /dev/null
+++ b/basic/qa/cppunit/test_vba.cxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "basictest.hxx"
+#include <unotools/syslocaleoptions.hxx>
+
+#ifdef _WIN32
+#include <string.h>
+#include <comphelper/processfactory.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <odbcinst.h>
+#endif
+
+using namespace ::com::sun::star;
+
+namespace
+{
+ class VBATest : public test::BootstrapFixture
+ {
+ public:
+ VBATest() : BootstrapFixture(true, false) {}
+ void testMiscVBAFunctions();
+ void testMiscOLEStuff();
+ // Adds code needed to register the test suite
+ CPPUNIT_TEST_SUITE(VBATest);
+
+ // Declares the method as a test to call
+ CPPUNIT_TEST(testMiscVBAFunctions);
+ CPPUNIT_TEST(testMiscOLEStuff);
+
+ // End of test suite definition
+ CPPUNIT_TEST_SUITE_END();
+
+ };
+
+void VBATest::testMiscVBAFunctions()
+{
+ const char* macroSource[] = {
+ "bytearraystring.vb",
+#ifdef _WIN32
+ "cdec.vb", // currently CDec is implemented only on Windows
+#endif
+ "constants.vb",
+// datevalue test seems to depend on both locale and language
+// settings, should try and rewrite the test to deal with that
+// for some reason tinderboxes don't seem to complain leaving enabled
+// for the moment
+ "datevalue.vb",
+ "partition.vb",
+ "strconv.vb",
+ "dateserial.vb",
+ "format.vb",
+ "replace.vb",
+ "stringplusdouble.vb",
+ "chr.vb",
+ "chrw.vb",
+ "abs.vb",
+ "array.vb",
+ "asc.vb",
+ "atn.vb",
+ "booltypename.vb",
+ "cbool.vb",
+ "cdate.vb",
+ "cdbl.vb",
+ "choose.vb",
+ "cos.vb",
+ "cint.vb",
+ "clng.vb",
+ "collection.vb",
+ "csng.vb",
+ "cstr.vb",
+ "cvdate.vb",
+ "cverr.vb",
+ "dateadd.vb",
+ "datediff.vb",
+ "datepart.vb",
+ "day.vb",
+ "enum.vb",
+ "error.vb",
+ "error_message.vb",
+ "Err.Raise.vb",
+ "exp.vb",
+ "fix.vb",
+ "hex.vb",
+ "hour.vb",
+ "formatnumber.vb",
+ "formatpercent.vb",
+ "iif.vb",
+ "instr.vb",
+ "instrrev.vb",
+ "int.vb",
+ "iserror.vb",
+ "ismissing.vb",
+ "isnull.vb",
+ "isobject.vb",
+ "join.vb",
+ "lbound.vb",
+ "isarray.vb",
+ "isdate.vb",
+ "isempty.vb",
+ "isnumeric.vb",
+ "lcase.vb",
+ "left.vb",
+ "len.vb",
+ "log.vb",
+ "ltrim.vb",
+ "mid.vb",
+ "minute.vb",
+ "month.vb",
+ "monthname.vb",
+ "oct.vb",
+ "optional_paramters.vb",
+ "qbcolor.vb",
+ "rgb.vb",
+ "rtrim.vb",
+ "right.vb",
+ "second.vb",
+ "sgn.vb",
+ "sin.vb",
+ "space.vb",
+ "split.vb",
+ "sqr.vb",
+ "str.vb",
+ "strcomp.vb",
+ "string.vb",
+ "strreverse.vb",
+ "switch.vb",
+ "tdf147089_idiv.vb",
+ "tdf147529_optional_parameters_msgbox.vb",
+ "tdf148358_non_ascii_names.vb",
+ "timeserial.vb",
+ "timevalue.vb",
+ "trim.vb",
+ "typename.vb",
+ "ubound.vb",
+ "ucase.vb",
+ "val.vb",
+ "vartype.vb",
+ "weekday.vb",
+ "weekdayname.vb",
+ "year.vb",
+#ifndef _WIN32 // missing 64bit Currency marshalling.
+ "win32compat.vb", // windows compatibility hooks.
+#endif
+ "win32compatb.vb" // same methods, different signatures.
+ };
+ OUString sMacroPathURL = m_directories.getURLFromSrc(u"/basic/qa/vba_tests/");
+ OUString sMacroUtilsURL = m_directories.getURLFromSrc(u"/basic/qa/cppunit/_test_asserts.vb");
+ // Some test data expects the uk locale
+ LanguageTag aLocale(LANGUAGE_ENGLISH_UK);
+ SvtSysLocaleOptions aLocalOptions;
+ aLocalOptions.SetLocaleConfigString( aLocale.getBcp47() );
+
+ for ( size_t i=0; i<std::size( macroSource ); ++i )
+ {
+ OUString sMacroURL = sMacroPathURL
+ + OUString::createFromAscii( macroSource[ i ] );
+
+ MacroSnippet myMacro;
+ myMacro.LoadSourceFromFile("TestUtil", sMacroUtilsURL);
+ myMacro.LoadSourceFromFile("TestModule", sMacroURL);
+ SbxVariableRef pReturn = myMacro.Run();
+ CPPUNIT_ASSERT_MESSAGE("No return variable huh?", pReturn.is());
+ fprintf(stderr, "macro result for %s\n", macroSource[i]);
+ fprintf(stderr, "macro returned:\n%s\n",
+ OUStringToOString(pReturn->GetOUString(), RTL_TEXTENCODING_UTF8).getStr());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Result not as expected", OUString("OK"),
+ pReturn->GetOUString());
+ }
+}
+
+void VBATest::testMiscOLEStuff()
+{
+// Not much point even trying to run except on Windows.
+// (Without Excel doesn't really do anything anyway,
+// see "so skip test" below.)
+
+// Since some time, on a properly updated Windows 10, this works
+// only with a 64-bit LibreOffice
+
+#if defined(_WIN64)
+ // test if we have the necessary runtime environment
+ // to run the OLE tests.
+ uno::Reference< lang::XMultiServiceFactory > xOLEFactory;
+ uno::Reference< uno::XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ if( xContext.is() )
+ {
+ uno::Reference<lang::XMultiComponentFactory> xSMgr = xContext->getServiceManager();
+ xOLEFactory.set( xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
+ uno::UNO_QUERY );
+ }
+ bool bOk = false;
+ if( xOLEFactory.is() )
+ {
+ uno::Reference< uno::XInterface > xADODB = xOLEFactory->createInstance( "ADODB.Connection" );
+ bOk = xADODB.is();
+ }
+ if ( !bOk )
+ return; // can't do anything, skip test
+
+ const int nBufSize = 1024 * 4;
+ wchar_t sBuf[nBufSize];
+ SQLGetInstalledDriversW( sBuf, nBufSize, nullptr );
+
+ const wchar_t *pODBCDriverName = sBuf;
+ bool bFound = false;
+ for (; wcslen( pODBCDriverName ) != 0; pODBCDriverName += wcslen( pODBCDriverName ) + 1 ) {
+ if( wcscmp( pODBCDriverName, L"Microsoft Excel Driver (*.xls)" ) == 0 ||
+ wcscmp( pODBCDriverName, L"Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)" ) == 0 ) {
+ bFound = true;
+ break;
+ }
+ }
+ if ( !bFound )
+ return; // can't find ODBC driver needed test, so skip test
+
+ const char* macroSource[] = {
+ "ole_ObjAssignNoDflt.vb",
+ "ole_ObjAssignToNothing.vb",
+ };
+
+ OUString sMacroPathURL = m_directories.getURLFromSrc(u"/basic/qa/vba_tests/");
+
+ // path to test document
+ OUString sPath = m_directories.getPathFromSrc(u"/basic/qa/vba_tests/data/ADODBdata.xls");
+ sPath = sPath.replaceAll( "/", "\\" );
+
+ uno::Sequence< uno::Any > aArgs
+ {
+ uno::Any(sPath),
+ uno::Any(OUString(o3tl::toU(pODBCDriverName)))
+ };
+
+ for ( sal_uInt32 i=0; i<std::size( macroSource ); ++i )
+ {
+ OUString sMacroURL = sMacroPathURL
+ + OUString::createFromAscii( macroSource[ i ] );
+ MacroSnippet myMacro;
+ myMacro.LoadSourceFromFile("TestModule", sMacroURL);
+ SbxVariableRef pReturn = myMacro.Run( aArgs );
+ CPPUNIT_ASSERT_MESSAGE("No return variable huh?", pReturn.is());
+ fprintf(stderr, "macro result for %s\n", macroSource[i]);
+ fprintf(stderr, "macro returned:\n%s\n",
+ OUStringToOString(pReturn->GetOUString(), RTL_TEXTENCODING_UTF8).getStr());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Result not as expected", OUString("OK"),
+ pReturn->GetOUString());
+ }
+#else
+ // Avoid "this method is empty and should be removed" warning
+ (void) 42;
+#endif
+}
+
+ // Put the test suite in the registry
+ CPPUNIT_TEST_SUITE_REGISTRATION(VBATest);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */