From d7bbf661e9065f1c894898f6ec2b9226d7777e46 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Sun, 16 Apr 2023 21:08:32 +0200 Subject: [PATCH 01/29] Standalone creation Refactor for structureFolder concept Create default settings Copy Volume Desktop to destinationFolder Rename Volume Desktop folder and exec Integrate structureFolder Sign --- .gitignore | 11 +- .../Sources/Classes/CompiledProject.4dm | 4 +- Build4D/Project/Sources/Classes/Component.4dm | 5 +- .../Project/Sources/Classes/Standalone.4dm | 39 +++ Build4D/Project/Sources/Classes/_core.4dm | 227 +++++++++++------- Build4D/Project/Sources/catalog.4DCatalog | 2 +- Build4D/Resources/Standalone.json | 23 ++ Build4D/Resources/en.lproj/syntaxEN.json | 35 ++- Build4D/Settings/buildApp.4DSettings | 21 +- .../Project/Sources/catalog.4DCatalog | 2 +- 10 files changed, 263 insertions(+), 106 deletions(-) create mode 100644 Build4D/Project/Sources/Classes/Standalone.4dm create mode 100644 Build4D/Resources/Standalone.json diff --git a/.gitignore b/.gitignore index 2025223..f3f8c6e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ userPreferences.*/ # Other Project/Trash -Settings/buildApp.4DSettings # System files .DS_Store @@ -24,7 +23,9 @@ Thumbs.db UT_*.log Build_*.log Artifacts/ -Test/ -Build/ -Build4D_UnitTests_Build/ -Build4D_External_Build/ +zzz*.4dm + +# Build +*Test/ +*buildApp.4DSettings +*Build/ diff --git a/Build4D/Project/Sources/Classes/CompiledProject.4dm b/Build4D/Project/Sources/Classes/CompiledProject.4dm index 8f70a84..ea4d93f 100644 --- a/Build4D/Project/Sources/Classes/CompiledProject.4dm +++ b/Build4D/Project/Sources/Classes/CompiledProject.4dm @@ -9,6 +9,7 @@ Class constructor($customSettings : Object) If (This._isDefaultDestinationFolder) This.settings.destinationFolder:=This.settings.destinationFolder.folder("CompiledProject/"+This.settings.buildName+"/") End if + This._structureFolder:=This.settings.destinationFolder End if //MARK:- @@ -27,5 +28,4 @@ Function build()->$success : Boolean "function"; "Build"; "message"; \ "Compiled project build successful."; \ "messageSeverity"; Information message)) - End if - \ No newline at end of file + End if \ No newline at end of file diff --git a/Build4D/Project/Sources/Classes/Component.4dm b/Build4D/Project/Sources/Classes/Component.4dm index 8353c82..7000a20 100644 --- a/Build4D/Project/Sources/Classes/Component.4dm +++ b/Build4D/Project/Sources/Classes/Component.4dm @@ -2,7 +2,6 @@ Class extends _core //MARK:- Class constructor($customSettings : Object) - // TODO: Include documentation of private functions and shared methods in the includePaths collection. Super("Component"; $customSettings) @@ -11,6 +10,7 @@ Class constructor($customSettings : Object) This.settings.destinationFolder:=This.settings.destinationFolder.folder("Component/") End if This.settings.destinationFolder:=This.settings.destinationFolder.folder(This.settings.buildName+".4dbase/") + This._structureFolder:=This.settings.destinationFolder End if //MARK:- @@ -32,5 +32,4 @@ Function build()->$success : Boolean "function"; "Build"; \ "message"; "Component build successful."; \ "messageSeverity"; Information message)) - End if - \ No newline at end of file + End if \ No newline at end of file diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm new file mode 100644 index 0000000..e92b4ff --- /dev/null +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -0,0 +1,39 @@ +Class extends _core + +//MARK:- +Class constructor($customSettings : Object) + + Super("Standalone"; $customSettings) + + If (This._validInstance) + If (This._isDefaultDestinationFolder) + This.settings.destinationFolder:=This.settings.destinationFolder.folder("Standalone/") + End if + This.settings.destinationFolder:=This.settings.destinationFolder.folder(This.settings.buildName+Choose(Is macOS; ".app"; "")+"/") + This._structureFolder:=This.settings.destinationFolder.folder(Choose(Is macOS; "Contents/"; "")+"Database/") + End if + + //MARK:- +Function build()->$success : Boolean + + $success:=This._validInstance + $success:=($success) ? This._checkDestinationFolder() : False + $success:=($success) ? This._copySourceApp() : False + $success:=($success) ? This._compileProject() : False + $success:=($success) ? This._createStructure() : False + $success:=($success) ? This._includePaths(This.settings.includePaths) : False + $success:=($success) ? This._deletePaths(This.settings.deletePaths) : False + $success:=($success) ? This._create4DZ() : False + $success:=($success) ? This._setAppOptions() : False + $success:=($success) ? This._generateLicenses() : False + If (Is macOS) + $success:=($success) ? This._sign() : False + End if + + If ($success) + This._log(New object(\ + "function"; "Build"; \ + "message"; "Standalone application build successful."; \ + "messageSeverity"; Information message)) + End if + \ No newline at end of file diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 4053d86..2e89c47 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -3,61 +3,56 @@ Class constructor($target : Text; $customSettings : Object) var $settings : Object - If (Application version<"1940") - ALERT("Minimum version to use this component is 4D v19 R4!") - Else - - This.logs:=New collection - This.settings:=New object() - This.settings.includePaths:=New collection - This.settings.deletePaths:=New collection - - If (File("/RESOURCES/"+$target+".json").exists) - This._overrideSettings(JSON Parse(File("/RESOURCES/"+$target+".json").getText())) // Loads target default settings + This.logs:=New collection + This.settings:=New object() + This.settings.includePaths:=New collection + This.settings.deletePaths:=New collection + + If (File("/RESOURCES/"+$target+".json").exists) + This._overrideSettings(JSON Parse(File("/RESOURCES/"+$target+".json").getText())) // Loads target default settings + End if + This._isDefaultDestinationFolder:=False + + $settings:=($customSettings#Null) ? $customSettings : New object() + + This._validInstance:=True + This._isCurrentProject:=True + This._projectFile:=File(Structure file(*); fk platform path) + If (($settings#Null) && ($settings.projectFile#Null) && ($settings.projectFile#"")) + This._isCurrentProject:=False + This._projectFile:=This._resolvePath($settings.projectFile; Folder("/PACKAGE/"; *)) + If (Not(This._projectFile.exists)) + This._validInstance:=False + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Project file doesn't exist, instanciated object is unusable."; \ + "severity"; Error message)) End if - This._isDefaultDestinationFolder:=False - - $settings:=($customSettings#Null) ? $customSettings : New object() - - This._validInstance:=True - This._isCurrentProject:=True - This._projectFile:=File(Structure file(*); fk platform path) - If (($settings#Null) && ($settings.projectFile#Null) && ($settings.projectFile#"")) - This._isCurrentProject:=False - This._projectFile:=This._resolvePath($settings.projectFile; Folder("/PACKAGE/"; *)) - If (Not(This._projectFile.exists)) - This._validInstance:=False - This._log(New object(\ - "function"; "Class constuctor"; \ - "message"; "Project file doesn't exist, instanciated object is unusable."; \ - "severity"; Error message)) - End if + End if + + This._projectPackage:=This._projectFile.parent.parent + + If (This._validInstance) + This._overrideSettings($settings) + If ((This.settings.buildName=Null) || (This.settings.buildName="")) + This.settings.buildName:=This._projectFile.name + This._log(New object(\ + "function"; "Settings checking"; \ + "message"; "Build name automatically defined."; \ + "severity"; Information message)) End if - - This._projectPackage:=This._projectFile.parent.parent - - If (This._validInstance) - This._overrideSettings($settings) - If ((This.settings.buildName=Null) || (This.settings.buildName="")) - This.settings.buildName:=This._projectFile.name - This._log(New object(\ - "function"; "Settings checking"; \ - "message"; "Build name automatically defined."; \ - "severity"; Information message)) - End if - If (This.settings.destinationFolder=Null) - This.settings.destinationFolder:=This._projectPackage.parent.folder(This._projectFile.name+"_Build/") - This._isDefaultDestinationFolder:=True - This._log(New object(\ - "function"; "Settings checking"; \ - "message"; "Destination folder automatically defined."; \ - "severity"; Information message)) - End if + If (This.settings.destinationFolder=Null) + This.settings.destinationFolder:=This._projectPackage.parent.folder(This._projectFile.name+"_Build/") + This._isDefaultDestinationFolder:=True This._log(New object(\ - "function"; "Class constuctor"; \ - "message"; "Class init successful."; \ + "function"; "Settings checking"; \ + "message"; "Destination folder automatically defined."; \ "severity"; Information message)) End if + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init successful."; \ + "severity"; Information message)) End if //MARK:- @@ -70,7 +65,6 @@ Function _overrideSettings($settings : Object) For each ($entry; $entries) Case of : ($entry.key="destinationFolder") - //$settings.destinationFolder:=($settings.destinationFolder="@/") ? $settings.destinationFolder : $settings.destinationFolder+"/" This.settings.destinationFolder:=This._resolvePath($settings.destinationFolder; This._projectPackage) If (Not(OB Instance of(This.settings.destinationFolder; 4D.Folder))) This._validInstance:=False @@ -80,6 +74,19 @@ Function _overrideSettings($settings : Object) : ($entry.key="includePaths") This.settings.includePaths:=This.settings.includePaths.concat($settings.includePaths) + + : ($entry.key="sourceAppFolder") + $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" + This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; Null) + If ((This.settings.sourceAppFolder=Null) || (Not(OB Instance of(This.settings.sourceAppFolder; 4D.Folder)) || (Not(This.settings.sourceAppFolder.exists)))) + This._validInstance:=False + This._log(New object(\ + "function"; "Source application folder checking"; \ + "message"; "Source application folder doesn't exist"; \ + "severity"; Error message); \ + "sourceAppFolder"; $settings.sourceAppFolder) + End if + Else This.settings[$entry.key]:=$entry.value End case @@ -114,7 +121,7 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) : Object Case of : ($path="/4DCOMPONENTS/@") $app:=(Is macOS) ? Folder(Application file; fk platform path).folder("Contents/Components") : File(Application file; fk platform path).parent.folder("Components") - $path:=$app.path+Substring($path; 15) + $absolutePath:=$app.path+Substring($path; 15) : (($path="") | ($path="/")) // Base folder $absolutePath:=$baseFolder.path @@ -134,15 +141,16 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) : Object Function _checkDestinationFolder()->$result : Boolean $result:=True - If (Not(This.settings.destinationFolder.exists)) - $result:=This.settings.destinationFolder.create() - If (Not($result)) - This._log(New object(\ - "function"; "Destination folder checking"; \ - "message"; "Destination folder doesn't exist and can't be created"; \ - "severity"; Error message); \ - "destinationFolder"; This.settings.destinationFolder.path) - End if + If (This.settings.destinationFolder.exists) // Delete destination folder if exists + This.settings.destinationFolder.delete(fk recursive) + End if + $result:=This.settings.destinationFolder.create() + If (Not($result)) + This._log(New object(\ + "function"; "Destination folder checking"; \ + "message"; "Destination folder doesn't exist and can't be created"; \ + "severity"; Error message); \ + "destinationFolder"; This.settings.destinationFolder.path) End if //MARK:- @@ -176,37 +184,37 @@ Function _compileProject() : Boolean //MARK:- Function _createStructure() : Boolean - var $destinationFolder; $librariesFolder : 4D.Folder + var $structureFolder; $librariesFolder : 4D.Folder var $deletePaths : Collection - + var $result : Boolean If (This._validInstance) - $destinationFolder:=This.settings.destinationFolder + $structureFolder:=This._structureFolder // Copy Project Folder - If ($destinationFolder.exists) // Empty the destination folder - $destinationFolder.delete(fk recursive) - $destinationFolder.create() + If ($structureFolder.exists) // Empty the structure folder + $structureFolder.delete(fk recursive) End if + $structureFolder.create() - This._projectFile.parent.copyTo($destinationFolder; fk overwrite) + This._projectFile.parent.copyTo($structureFolder; fk overwrite) // Remove source methods $deletePaths:=New collection - $deletePaths.push($destinationFolder.folder("Project/Sources/Classes/")) - $deletePaths.push($destinationFolder.folder("Project/Sources/DatabaseMethods/")) - $deletePaths.push($destinationFolder.folder("Project/Sources/Methods/")) - $deletePaths.push($destinationFolder.folder("Project/Sources/Triggers/")) - $deletePaths.push($destinationFolder.folder("Project/Trash/")) + $deletePaths.push($structureFolder.folder("Project/Sources/Classes/")) + $deletePaths.push($structureFolder.folder("Project/Sources/DatabaseMethods/")) + $deletePaths.push($structureFolder.folder("Project/Sources/Methods/")) + $deletePaths.push($structureFolder.folder("Project/Sources/Triggers/")) + $deletePaths.push($structureFolder.folder("Project/Trash/")) If (This._deletePaths($deletePaths)) - $deletePaths:=$destinationFolder.files(fk recursive).query("extension =:1"; ".4DM") // Table Form, Form and Form object methods + $deletePaths:=$structureFolder.files(fk recursive).query("extension =:1"; ".4DM") // Table Form, Form and Form object methods If (($deletePaths.length>0) || (This._deletePaths($deletePaths))) // Copy Libraries folder $librariesFolder:=This._projectPackage.folder("Libraries") If (($librariesFolder.exists) && ($librariesFolder.files.length)) - $librariesFolder.copyTo($destinationFolder; fk overwrite) + $librariesFolder.copyTo($structureFolder; fk overwrite) End if return True End if @@ -243,11 +251,11 @@ Function _includePaths($pathsObj : Collection) : Boolean End if If (Undefined($pathObj.destination)) - $destinationPath:=This.settings.destinationFolder + $destinationPath:=This._structureFolder Else Case of : (Value type($pathObj.destination)=Is text) - $destinationPath:=This._resolvePath($pathObj.destination; This.settings.destinationFolder) + $destinationPath:=This._resolvePath($pathObj.destination; This._structureFolder) : (OB Instance of($pathObj.destination; 4D.Folder)) $destinationPath:=$pathObj.destination Else @@ -312,7 +320,7 @@ Function _deletePaths($paths : Collection) : Boolean Case of : (Value type($path)=Is text) - $deletePath:=This._resolvePath($path; This.settings.destinationFolder) + $deletePath:=This._resolvePath($path; This._structureFolder) : ((OB Instance of($path; 4D.Folder)) || (OB Instance of($path; 4D.File))) $deletePath:=$path Else @@ -349,18 +357,18 @@ Function _deletePaths($paths : Collection) : Boolean //MARK:- Function _create4DZ() : Boolean - var $destinationFolder : 4D.Folder + var $structureFolder : 4D.Folder var $zipStructure : Object var $return : Object If ((This._validInstance) && (This.settings.packedProject)) - $destinationFolder:=This.settings.destinationFolder + $structureFolder:=This._structureFolder $zipStructure:=New object - $zipStructure.files:=New collection($destinationFolder.folder("Project")) + $zipStructure.files:=New collection($structureFolder.folder("Project")) $zipStructure.encryption:=(This.settings.obfuscated) ? -1 : ZIP Encryption none - $return:=ZIP Create archive($zipStructure; $destinationFolder.file(This.settings.buildName+".4DZ")) + $return:=ZIP Create archive($zipStructure; $structureFolder.file(This.settings.buildName+".4DZ")) If ($return.success) - $destinationFolder.folder("Project").delete(Delete with contents) + $structureFolder.folder("Project").delete(Delete with contents) Else This._log(New object(\ "function"; "Package compression"; \ @@ -372,6 +380,59 @@ Function _create4DZ() : Boolean End if return True + //MARK:- +Function _copySourceApp() : Boolean + var $sourceApp; $components4D; $destination; $copiedFolder : 4D.Folder + var $executable : 4D.File + + $sourceApp:=This.settings.sourceAppFolder + $destination:=This.settings.destinationFolder + + //TODO: check applications versions + + $sourceApp.copyTo($destination.parent; $destination.fullName) + + If (Application type#6) //tool4d doesn't embed components + $components4D:=This._resolvePath("/4DCOMPONENTS/"; Null) + $copiedFolder:=(Is macOS) ? $components4D.copyTo($destination.folder("Contents")) : $components4D.copyTo($destination) + End if + + If (Is macOS) + $executable:=$destination.file("Contents/MacOS/4D Volume Desktop") + $executable.rename(This.settings.buildName) + Else + $executable:=$destination.file("4D Volume Desktop.4DE") + $executable.rename(This.settings.buildName+".exe") + End if + + //TODO: add internal components + + return True + + //MARK:- +Function _setAppOptions() : Boolean + var $appInfo : Object + var $infoFile : 4D.File + + $appInfo:=New object(\ + "CFBundleDisplayName"; This.settings.buildName; \ + "CFBundleExecutable"; This.settings.buildName\ + ) + + If (Is macOS) + $infoFile:=This.settings.destinationFolder.file("Contents/Info.plist") + Else + End if + $res:=$infoFile.setAppInfo($appInfo) + + return True + + //MARK:- +Function _generateLicenses() : Boolean + //TODO: Licenses generation + //Create deployment license() + return True + //MARK:- Function _sign() : Boolean diff --git a/Build4D/Project/Sources/catalog.4DCatalog b/Build4D/Project/Sources/catalog.4DCatalog index 553f52b..f42fe38 100644 --- a/Build4D/Project/Sources/catalog.4DCatalog +++ b/Build4D/Project/Sources/catalog.4DCatalog @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/Build4D/Resources/Standalone.json b/Build4D/Resources/Standalone.json new file mode 100644 index 0000000..cc26e13 --- /dev/null +++ b/Build4D/Resources/Standalone.json @@ -0,0 +1,23 @@ +{ + "//target":"Standalone", + "packedProject":true, + "obfuscated4DZ":false, + "lastDataPathLookup":"ByAppName", + "includePaths": + [ + { + "source":"./Libraries/", + "destination":"./" + }, + { + "source":"./Resources/", + "destination":"./" + } + ], + "deletePaths":[], + "signApplication":{ + "macSignature":false, + "macCertificate":"", + "adHocSignature":true + } +} \ No newline at end of file diff --git a/Build4D/Resources/en.lproj/syntaxEN.json b/Build4D/Resources/en.lproj/syntaxEN.json index 94522ca..ce73ccb 100644 --- a/Build4D/Resources/en.lproj/syntaxEN.json +++ b/Build4D/Resources/en.lproj/syntaxEN.json @@ -1,7 +1,20 @@ { "_method_": {}, "cs.Build4D": { - "Component": { + "CompiledProject": { + "new()": { + "Syntax": "**.new**( *customSettings* : Object )", + "Params": [ + [ + "customSettings", + "Object", + "->" + ] + ], + "Summary": "" + } + }, + "Standalone": { "new()": { "Syntax": "**.new**( *customSettings* : Object )", "Params": [ @@ -32,7 +45,7 @@ "Summary": "" } }, - "CompiledProject": { + "Component": { "new()": { "Syntax": "**.new**( *customSettings* : Object )", "Params": [ @@ -46,7 +59,21 @@ } } }, - "Component": { + "CompiledProject": { + "build()": { + "Syntax": "**.build**()->success : Boolean", + "Params": [ + [ + "success", + "Boolean", + "<-" + ] + ], + "Summary": "" + }, + "_inheritedFrom_": "_core" + }, + "Standalone": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ @@ -61,7 +88,7 @@ "_inheritedFrom_": "_core" }, "_core": {}, - "CompiledProject": { + "Component": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index 75ea34f..996bb45 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -2,17 +2,18 @@ - False + True True True - False + True ByAppPath True - Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: + Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: + C:\Program Files\4D\4D v0.0\4D Volume Desktop\ False False @@ -30,7 +31,7 @@ Build4D - :Build: + ::Test: 0 @@ -46,14 +47,20 @@ 1 - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4UUD190UUS001BCKBT078EA.license4D + Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:4UUD200UUS0018PNC005EC7.license4D + + 2 + C:\ProgramData\4D\Licenses\R-4UUD200UUS0018PNC005EC7.license4D + C:\ProgramData\4D\Licenses\R-4DDP200UUS001APL8416796.license4D - True - Damien FUZEAU + False + True + ..\Build4D_Build\ + diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog index 20d010a..d041cf8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog +++ b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog @@ -2,7 +2,7 @@ - + \ No newline at end of file From 43b8e6397d3c705a0dd8b14413cd5cf4b2daabfc Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Tue, 18 Apr 2023 07:04:17 +0200 Subject: [PATCH 02/29] Checking sourceApp version --- Build4D/Project/Build4D.4DProject | 2 +- .../Project/Sources/Classes/Standalone.4dm | 20 ++++++++ Build4D/Project/Sources/Classes/_core.4dm | 49 +++++++++---------- Build4D/Project/Sources/Methods/onError.4dm | 1 + Build4D/Resources/en.lproj/syntaxEN.json | 9 +++- Build4D/Settings/buildApp.4DSettings | 2 +- 6 files changed, 53 insertions(+), 30 deletions(-) diff --git a/Build4D/Project/Build4D.4DProject b/Build4D/Project/Build4D.4DProject index 256d302..0d4876d 100644 --- a/Build4D/Project/Build4D.4DProject +++ b/Build4D/Project/Build4D.4DProject @@ -1,5 +1,5 @@ { "$comment": "The project file serves as an anchor to locate other project files", - "compatibilityVersion": 1950, + "compatibilityVersion": 2000, "tokenizedText": false } diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index e92b4ff..a893abf 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -13,12 +13,32 @@ Class constructor($customSettings : Object) This._structureFolder:=This.settings.destinationFolder.folder(Choose(Is macOS; "Contents/"; "")+"Database/") End if + //MARK:- +Function _copySourceApp() : Boolean + var $renamedExecutable : 4D.File + This.settings.sourceAppFolder.copyTo(This.settings.destinationFolder.parent; This.settings.destinationFolder.fullName) + If (Is macOS) + $renamedExecutable:=This.settings.destinationFolder.file("Contents/MacOS/4D Volume Desktop").rename(This.settings.buildName) + Else + $renamedExecutable:=This.settings.destinationFolder.file("4D Volume Desktop.4DE").rename(This.settings.buildName+".exe") + This.settings.destinationFolder.file("4D Volume Desktop.rsr").rename(This.settings.buildName+".rsr") + End if + If ($renamedExecutable.name#This.settings.buildName) + This._log(New object(\ + "function"; "Source app copy"; \ + "message"; "Unable to rename the app: '"+This.settings.buildName+"'"; \ + "severity"; Error message)) + return False + End if + return True + //MARK:- Function build()->$success : Boolean $success:=This._validInstance $success:=($success) ? This._checkDestinationFolder() : False $success:=($success) ? This._copySourceApp() : False + $success:=($success) ? This._excludeModules() : False $success:=($success) ? This._compileProject() : False $success:=($success) ? This._createStructure() : False $success:=($success) ? This._includePaths(This.settings.includePaths) : False diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 2e89c47..d52800a 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -1,5 +1,11 @@ +property _validInstance; _isCurrentProject; _isDefaultDestinationFolder; _noError : Boolean +property _projectFile : 4D.File +property _projectPackage; _structureFolder : 4D.Folder +property logs : Collection +property settings : Object + Class constructor($target : Text; $customSettings : Object) - ON ERR CALL("onError") + ON ERR CALL("onError"; ek global) var $settings : Object @@ -59,7 +65,7 @@ Class constructor($target : Text; $customSettings : Object) Function _overrideSettings($settings : Object) var $entries : Collection - var $entry : Object + var $entry; $currentAppInfo; $sourceAppInfo : Object $entries:=OB Entries($settings) For each ($entry; $entries) @@ -85,6 +91,18 @@ Function _overrideSettings($settings : Object) "message"; "Source application folder doesn't exist"; \ "severity"; Error message); \ "sourceAppFolder"; $settings.sourceAppFolder) + + Else // Versions checking + $sourceAppInfo:=(Is macOS) ? This.settings.sourceAppFolder.file("Contents/Info.plist").getAppInfo() : This.settings.sourceAppFolder.file("Resources/Info.plist").getAppInfo() + $currentAppInfo:=(Is macOS) ? Folder(Application file; fk platform path).file("Contents/Info.plist").getAppInfo() : File(Application file; fk platform path).parent.file("Resources/Info.plist").getAppInfo() + If (($sourceAppInfo.CFBundleVersion=Null) || ($currentAppInfo.CFBundleVersion=Null) || ($sourceAppInfo.CFBundleVersion#$currentAppInfo.CFBundleVersion)) + This._validInstance:=False + This._log(New object(\ + "function"; "Source application version checking"; \ + "message"; "Source application version doesn't match to current application version"; \ + "severity"; Error message); \ + "sourceAppFolder"; $settings.sourceAppFolder) + End if End if Else @@ -381,31 +399,8 @@ Function _create4DZ() : Boolean return True //MARK:- -Function _copySourceApp() : Boolean - var $sourceApp; $components4D; $destination; $copiedFolder : 4D.Folder - var $executable : 4D.File - - $sourceApp:=This.settings.sourceAppFolder - $destination:=This.settings.destinationFolder - - //TODO: check applications versions - - $sourceApp.copyTo($destination.parent; $destination.fullName) - - If (Application type#6) //tool4d doesn't embed components - $components4D:=This._resolvePath("/4DCOMPONENTS/"; Null) - $copiedFolder:=(Is macOS) ? $components4D.copyTo($destination.folder("Contents")) : $components4D.copyTo($destination) - End if - - If (Is macOS) - $executable:=$destination.file("Contents/MacOS/4D Volume Desktop") - $executable.rename(This.settings.buildName) - Else - $executable:=$destination.file("4D Volume Desktop.4DE") - $executable.rename(This.settings.buildName+".exe") - End if - - //TODO: add internal components +Function _excludeModules() : Boolean + //TODO: remove modules return True diff --git a/Build4D/Project/Sources/Methods/onError.4dm b/Build4D/Project/Sources/Methods/onError.4dm index cc9aaa1..21aa4de 100644 --- a/Build4D/Project/Sources/Methods/onError.4dm +++ b/Build4D/Project/Sources/Methods/onError.4dm @@ -1,2 +1,3 @@ //%attributes = {} This._log(New object("severity"; Error message; "callChain"; Get call chain; "errorCode"; Error; "errorMethod"; Error method; "errorLine"; Error line; "errorFormula"; Error formula)) +This._noError:=False diff --git a/Build4D/Resources/en.lproj/syntaxEN.json b/Build4D/Resources/en.lproj/syntaxEN.json index ce73ccb..c580f29 100644 --- a/Build4D/Resources/en.lproj/syntaxEN.json +++ b/Build4D/Resources/en.lproj/syntaxEN.json @@ -87,7 +87,14 @@ }, "_inheritedFrom_": "_core" }, - "_core": {}, + "_core": { + "logs": { + "Syntax": "logs : Collection" + }, + "settings": { + "Syntax": "settings : Object" + } + }, "Component": { "build()": { "Syntax": "**.build**()->success : Boolean", diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index 996bb45..5ac9ec0 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -59,7 +59,7 @@ True - ..\Build4D_Build\ + Z:\4D\GitHub\Build4D\Test\Legacy\win\ From 73f9c63b7d291bb0a791b029e0155bcfa656f13f Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Tue, 18 Apr 2023 23:25:35 +0200 Subject: [PATCH 03/29] Application icon integration --- .../Project/Sources/Classes/Standalone.4dm | 5 +- Build4D/Project/Sources/Classes/_core.4dm | 58 +++++++++++++++--- Build4D/Settings/buildApp.4DSettings | 18 ++++-- Build4D_UnitTests/Build4D.icns | Bin 0 -> 118181 bytes Build4D_UnitTests/Build4D.ico | Bin 0 -> 54340 bytes 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 Build4D_UnitTests/Build4D.icns create mode 100644 Build4D_UnitTests/Build4D.ico diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index a893abf..ef39747 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -14,9 +14,8 @@ Class constructor($customSettings : Object) End if //MARK:- -Function _copySourceApp() : Boolean +Function _renameExecutable() : Boolean var $renamedExecutable : 4D.File - This.settings.sourceAppFolder.copyTo(This.settings.destinationFolder.parent; This.settings.destinationFolder.fullName) If (Is macOS) $renamedExecutable:=This.settings.destinationFolder.file("Contents/MacOS/4D Volume Desktop").rename(This.settings.buildName) Else @@ -34,10 +33,10 @@ Function _copySourceApp() : Boolean //MARK:- Function build()->$success : Boolean - $success:=This._validInstance $success:=($success) ? This._checkDestinationFolder() : False $success:=($success) ? This._copySourceApp() : False + $success:=($success) ? This._renameExecutable() : False $success:=($success) ? This._excludeModules() : False $success:=($success) ? This._compileProject() : False $success:=($success) ? This._createStructure() : False diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index d52800a..a0ee517 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -81,6 +81,9 @@ Function _overrideSettings($settings : Object) : ($entry.key="includePaths") This.settings.includePaths:=This.settings.includePaths.concat($settings.includePaths) + : ($entry.key="iconPath") + This.settings.iconPath:=This._resolvePath($settings.iconPath; This._projectPackage) + : ($entry.key="sourceAppFolder") $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; Null) @@ -398,6 +401,11 @@ Function _create4DZ() : Boolean End if return True +Function _copySourceApp() : Boolean + This._noError:=True + This.settings.sourceAppFolder.copyTo(This.settings.destinationFolder.parent; This.settings.destinationFolder.fullName) + return This._noError + //MARK:- Function _excludeModules() : Boolean //TODO: remove modules @@ -407,20 +415,54 @@ Function _excludeModules() : Boolean //MARK:- Function _setAppOptions() : Boolean var $appInfo : Object - var $infoFile : 4D.File + var $infoFile; $exeFile : 4D.File - $appInfo:=New object(\ - "CFBundleDisplayName"; This.settings.buildName; \ - "CFBundleExecutable"; This.settings.buildName\ - ) + This._noError:=True If (Is macOS) + $infoFile:=This.settings.destinationFolder.file("Contents/Info.plist") - Else + + If ($infoFile.exists) + $appInfo:=New object(\ + "CFBundleDisplayName"; This.settings.buildName; \ + "CFBundleExecutable"; This.settings.buildName\ + ) + If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon + $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName + This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) + End if + $infoFile.setAppInfo($appInfo) + + Else + This._log(New object(\ + "function"; "Setting app options"; \ + "message"; "Info.plist file doesn't exist: "+$infoFile.path; \ + "severity"; Warning message)) + return False + End if + + Else // Windows + + $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") + + If ($exeFile.exists) + + If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon + $exeFile.setAppInfo(New object("WinIcon"; This.settings.iconPath)) + End if + + Else + This._log(New object(\ + "function"; "Setting app options"; \ + "message"; "Exe file doesn't exist: "+$exeFile.path; \ + "severity"; Warning message)) + return False + End if + End if - $res:=$infoFile.setAppInfo($appInfo) - return True + return This._noError //MARK:- Function _generateLicenses() : Boolean diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index 5ac9ec0..5cdb32b 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -15,14 +15,16 @@ Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: C:\Program Files\4D\4D v0.0\4D Volume Desktop\ - False - False + True + True False + Macintosh HD:Applications:4D v0.0:4D Server.app: + Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: - False - ByAppName + True + ByAppPath False False @@ -46,8 +48,10 @@ - 1 - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:4UUD200UUS0018PNC005EC7.license4D + 3 + Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4UUD200UUS0018PNC005EC7.license4D + Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4DTD200UUS001APL85125DE.license4D + Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4DDP200UUS001APL8416796.license4D 2 @@ -63,4 +67,6 @@ + + diff --git a/Build4D_UnitTests/Build4D.icns b/Build4D_UnitTests/Build4D.icns new file mode 100644 index 0000000000000000000000000000000000000000..5385610439e48fc59f8a7016f62014a6b781e406 GIT binary patch literal 118181 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 Pb?`DH6sgsy0f7GlQj^tX literal 0 HcmV?d00001 diff --git a/Build4D_UnitTests/Build4D.ico b/Build4D_UnitTests/Build4D.ico new file mode 100644 index 0000000000000000000000000000000000000000..1221738ca9cf06327c172f43fd465d08e17e77bb GIT binary patch literal 54340 zcmV)TK(W6700966000000096X06vZY09F7105C8B0096X0B9xv0F;gZ03aX$0096X z04Nav0Q|H702mkm0096X0JsSN03^l$01yxW0096X0B8gN0Nl?20EtjeM-2)Z3IG5A z4M|8uQUCw}0000100;&E003NasAd2F3PEW@Lr_UWLm*IcZ)Rz1WdHz34V{*ER8!d& zhtIt?z0eXOASLt~dI=!XJ4h7-QHe=_Py&X8CU!&xMidb#R%BGb0Y`@-V?`7TgMwn$ z3Gxt7#=%iUMdjU$YYFeIHS^w@{l{6~+2^;{*=O&4*SY{u{DK6+bXWm^G@)1&?(4x^ z5);eB_W~FY0S;IJz~N?Q1V{Kp0@VDyJ(-!PNXE1F?k<32yW1?kP$qNM|9_DpH$x-_ z018FbHavbN7v%z!Q?tbxGXDh1^pz2diz!JChX6iL5!YR-)!ux zFTEB3_9R-H9kafbRRFYY20-QEtWWPC0P+O@wBDTa9)@gQlEmT+Cku=0>}+!ZpKC5F z=r{YHf^W*dhB^0{%kKMDJEj*ufg?#3Gi62Prl+P$M9j<#4wuhl{r3?6x)S_pYV zK~Ojp1I0s$kPwnU`Oqe)7%GFRp+itT^doc{x(Ho^`k)8UAT$R30eyrKm;%#b4cGv- zfZ4D+90*6k%iu(K6`Thbz}w+UxE4MRx55|U8}I-ugz8{aPn6e}cb8u-pC?}-e@gzQ{I~*9!9c-N zfupcip+@1f!aapaMVg|OVu)gzVu@md;x)xlCA^Y>lD861sX*zl(j}!K8bZ^hdD6JF zO|&}NW!f+uM>nMV)064N^dIQG^a*7pWn1MawEHs!UaH)fCm8s%@%I)G%r$YGG>GYWvkL ztBud6&v%~BonJKnDz8V=CRT`Hx#x)t5ZkoxO<(lU- z$Fyi#3$+AVTBAG0IAgYPit#?N=#F}eeV|~Yl zYU5+G&ZgbwwXLZw-*&(4eLI?6u-z8BPP@*(RQ&hd=n2Pb$K8-#TzIMK=eJ}W7{Q~`V`rY%_@aOv1`%eTo1gr_@3Zw)^1Xc$=3o;231$6|& z!2!X$f*&u^UnE@A76L;2Lw1Ec2{jB|75Z}+E-W;xChU2*Rd{}QcLXhBMMOiyyGW17 z(#S`PjTTE5cSgxa#YNReO+|Y}mqkmLSS(qyy2@$Q?o|__K+%y*D05k6yO@stO!Y{NB%39JSqrmj zvfgJ$WuMAX%n|1FOu)bhuv+w4{Lb*aw;k_-+TMlf+Y!z(n-Db0` zYTK70UeWbp%i@aSPbJ)v>)%;@SNYw{_Jr-drS_%!ci?sicii3Sy7O3>Vp(3<(5~QJ zt>w(}qVl)9SM0u4VOw!v4{48NkF+wVvb{>LYDd+l>ZIy{8jqUhz3O|n?VZ}k+t!Rwqzh{46e?;v_@sZC*g-4~w!jE;; zJJi=Vs5g{0!i|!~vEy;aZ~fr)Lwgge=}K2|6bfZ>3!b) z(FdsyUO&uwIQ?k-W9;LiCkjt0o~l2s{nhx_W~sgO?4Z|R&$EbUkA}EIFaMSKuTR4T z&#BKVMzluiN3BQCjQNb+da?Ay@XL&s)8mD|DgL(imC>u8es}x5XJX03@N3cQnLkS2 zsJ=P+*7j}ZWa#A6cWLjYr;6UIzCZSX{h|9~^v99u>`(Ylm7k42cYF!_@^~g~X6E1b zg!B6{I$3@I06+jqL_t(|0qnhLuq?@S-&eidci(&SW_$BypTS@T`!XN^aRY4%ghg$p zX_5dfDPUU;MNl$nTOq@w5DwcP=m^W zfWTld00y(ZS>DXN{qDEB{r{blr@Fdtb$9jc<#ylKd2e-9Wo2gNIeE^>lP6DR)v_Z9 z%@1~JKlkCR-g$f0`1Y$==MR1-+uwh@)`_b8{3kk%iw|Uv>i+%hPWB$1-=^bX9S`cb zMMp!&Dy%TDXc*X0g)ZrMPRG+azMa*wZ?v=QtDpJB8uxklpMJAb|3)WkLjNDVCu@D; z?`54L59A4Fd{LWm`FZid^e?|XtNoK-sO{$ubOFP^{-*5yPAj{=R?F_Icd`eBv-q^>%iC z?L_wCKlod<*A$-z1j6S!S^dXrS$m$sU~U2+hcsOv5RiC3{oi!X)Yr53HEY?2gsdOZ zDP&sCTcz3Img3AZU13l>C$mdrVaQMX9h~zHmKz>hr%`+k^T4=Fite z{__trWiFWfC;ocYxJNzq-~EN!ZV|kX{c7h2bpIhCqn(aW#G3IoRz z1GP*_e|BELp&5Kf^#2uU3XgsI7i-@MfYFE<9@oB|wSM#0YORQ$#d#(I0LG`X{bQPc z?|#>3Jps013uepUTB}|1W>4^I)r< z{j`Ani{kEg>EZ2qd`3r^K`)R<5i_YH1+T&i12e`zk&by)87-q3U)AxN69214E&HA3 zPWHS1;J>I5m;Hyo(K+!-mbI}B%wm{ORw3SdsK8j}Gp}R~#x+rZF@7!kpzi;59Us<# z>R$|`1yRx4$GMnhb-lvCalim{jyAv%G>=vg0R!R}^xz9(%*WIqXes#hQ*4(+5UY=M@HeF%ZK8I!OFo2;1VL-x1UN zmLk9K+rLzM-J`RtjQ`?U)$^eR05AVJdGozTN`4q8KKd)29~ATd$9g#y{yTNR@DY%7 zhkjoavO2FYaLh3PpAd??vZ2Ul6!Cvb8~D4Q`K8)(@E=p`(ga$QXadET_-iZt#yCHc z{^eio+_c-tKCHt2T^)@1Z%WUY&O@qU>5uV$dbB!C6$6QEaw&VLmK{+e6`q$*(pkJ? zL=|qJ$M6oCzD=RK=1OANp}Fh4SvgO2neUHwfRf9q#H)%iZ%TR05k zN8YiTk)EH7q4NLquXfJKxA`YUbbn3JKN^MVi~s7@g+{ z!`3hbY-mMFWC3YVTmdV5FQSi$}dqB=c=*HYah z@#;JV22u-J)4@{&9EE;YDE@mNxh4A?{D|+(-~W9R5(gacEXRPKz9t=zO40oW2dVvc z?X|O?sMWK-uBv?~<=oQwgpR0aie8<@#X!#BeHo33jgjrg7|nQ358_M~n6sU1%N^bD z*CvH&jJi{LyEl#}XHCAR!RQbzy{)pUJI1%WhBXnxw@*-B;nz z7yx^;D6<1$ApA#SwBOh{ll`G)2r#lA;8Ws;h2pfsz;t2o`_0GQMfYd_PUj9|{w(`X zMN{u9WJG0g3MfRbE{9{l_#!a}Ow<$NUe96Z7KeWJTP-`c6xnIFvVG1iF*axZD33gO zVd(|j7cTS1aS`vc`|eHj{%8qxNrZ-6)@nNHk_-rrMx&9{8}+PNZ|IumDj>2Scpvri zhX>$|daTa<7yw~l)s(&T@MBW7Z);x9{*LZHANGL$&N`(nJyj9_Hpcj{w;~3=y^g8< z^!&m6;rUmz`j@_N71_l=5I<)aj9$AVj&(+F>#Rc&c9uzK-@0}6+{Eh|=I^F~`Spwf z@~+mIEN8^-tE*pGv-6Y6(iKc!SEUgEboB^;rs8VE+gWh}$bT*?9WIdT>ML)>eN5|w`;!#9zOERowYyE_5xLG0~9he6fOS$ z!7q1CUppgfe<%CTmFZ8Xj8taD_(QQ+?IBFPzu(FB_FCB#(yv$w?H`!Ksy z`hA$Zowbw^VGzB$_w1>w1gmOo@m3!4vh$cZUZ`3OIS2xY8~+guE!ES7S}WVlHGmz{ z9vCLnB?u4-YmKIz>!L>B66jVA_;X{T+ZQN#6?!n>h*y+4WmeW+`*(h&^Xvb|Cu?6P zmHY(O|H&_8W*gwXEELG7_i?f3=ZV(uzgvy_30?kNO3A{7)$TkA8D*#7d7g={jhNdo zx5ny>;v;ql%H3rYFpg{AG)E0qA)hgZZhVQIX)%MHfEdMTX4X zoxN;hb1S=iRXDkHHM@LyBfGk>lWp%X^yx2Aq|$m4$r*f6-GqLaN}5!YlwdR%c|0DSxd z25A8Yn3#n0{>o>Wq+9%XG5=pt>Gx8Y0#gx1yj$dr{$s=_tZ?4fSbk@BFWb@fF55a| zz$+3bL=5AP6S@pEPOj;von}3(EdB6T?4nu{lpG9R!4=HEzP_HF)PVs}lL@)7Ekbw$ z6D7oi>u{j)y}JIll#8N%5k1&Ta$viAxfAOD$O>1_SuPu89wGKTjlMK43M`5+HI{@-@iHU46M{vXx>(=!~S z=kFG-n;RiOKoAwg)RHl8SJr%tdAm&Esn_3QjE~h%0V3tV8xGDX60jwx_)}yqvP8L1 zGhTQ4w?I03GcO8eNpV`8nWrH+gBEXI9zwr`J!Ib`ZFlV=WfpRWt)0x-85CEuT`vuYcx~we#E)VphNmdPyy? z2klGQ&7!BD(9Mrpg#RRSS0Uz@UPkZhMD4x)hRxq!&#qtJ6!Y)O=;zaTk@m2tAb;^d zp5QM}4|d`NjxiXy#PFuq%1s#OAx)9xo`ZJn%zvPpQ;U1=$2*)Ui|?u)=XG?>E<#G7 z7&>)mIF#231E}t?k3f3BgB5>GMmykPyl%pxuTI61$Gr|%SSx`Mc1wN*SFT>quFzh( zCq#R4J!!j9#u9|QdlFhcq?;fAH~)vu%~5am@#NaZ^!I+-n%AC5gL+U;en{s6n1870%0a!>gB#@r6m|CSy_z-O4N01D%oi@{ltV2Ls@%J94>4sEc(H?>1u-CPO zn)eH>f9~eC`32xDm_6~7lSebD|1DI4k9|D5Qv&=$dj1fJ6ey^d-Yoif{RlaUSsbpt z{Z6(aRex8#J>z{;Ymto-=`3tI@sMl$0Fm<#^Rr0Cgo*CyF>Q69giiFHUb-^{*ARMd zO}RhXFsx26Bi??D*CP;T%qnIyZ9sShUbGt-4wMXdVbaJ^?cCcYDw~p2-sa}E4c$&i z137(4z62-NgmZgMwSt#76&MWPfHS)OQ|i;+rt>p^6wX2RMN%Sg5Rm5fLAA$6)C}Q9 zNFif31*I)XFk(dQcIMiX^xN3jbyZ&ifH6OF`bM+@$yM>{u#t}ghKJ}OcvI`KPU+r^ zWMU3m!%z24di}u=wh+jkd4Ap+jZt>4UaRS)EUQN`jyD+&0!9RZ;lp79elzCjY-3FI z&dl+%J|J+N<8X{>`vxY|1i|Y58O+#RmoT`#fk43Z+L~Z&K{G}*7A2`8BFpYlg?>hshfc=jrlR~X}r%8TquLb7~cq@ zm-NF$wE)xSLD%&9^!PT#W<5QQLU{_iAV*KW-p2#)3U3;iX5J61PDLCPDu977U^iwI znh}s}EJA?sC3+8q3mOYSN-&&Tc}&|fl-t#m;fd_D429TPd^l%GkK<2~EKUi)kBHR2 ztIqy=0E_LfdCT37slWKM**RUkO9{f|mlZ}>5sQV8?-&FpEC7Sow?r7s=d(Hw<~M>A zGR9>@@`aSBC1QsDy+?O7w;}Zw;x-|Wr%p&7z$}z{?1Cf9iO(pkrXdheGQH=c0o!HB z^mW~*p#-=ijN3N6h@2h0WNS-?T&cTF4GT_cw&3J?QyK^DM9HK&HYD%8mk$M4xl8B% zWexj3%|3!m2{!rK2;UrQUd!I8&gg+-1G*qB3&1DVw#H`Mxg*tZb8E{CN3=bJA*-xV913NQC-738-mEi<%DJ^D4+LG^f3$QnW$DL z1=_=(y+K+)D0p5g7HrXOryC$0PnB($$znK1mTIKuC zf9n@&8$MM~*ZQA!_NRory8t|e;~@Zm2jbB|o8!S}Q+w(Gu=2M%E%nv{m7XTGy|sQ| zAwS1Mv3tT1gxAnKJprP0&B8~Y;R(kxie81oVIX&}R^u3sCA0 zTnEBaL)nw!Ptq(XNtyTB``Kn^M?zcfuIpN4BqJokoZQjY#oSAHUF79+g6sWzyV%&| z)@*yNb!h|Z(gu!|fv}4Rb@H0cepFxh_?!@s1VBv!Aj=*GB?`DsvB_sQ6R}Gg)KS=Y zpD`Z`NOslGc&-t=w@4H<0zU5v7%Dj7nHW%{mxWPJA$1q@R7JuaQS|EZSQwza+;@Pn z9L7`xF^)chF@YL zsg8^zOqt_XIJZ3%)y8d`aq<2NVZe9~!Jq~*p+MBAU~4Q?CcOnhU|+%oT0tAIy$a3t zFshV=e~!_lE)&%QwRRE!wYBW~grEBadV~t-ilmEsrY%{(1LL#rUbojz;1vKK1_k99 zO^L{wGD7W3#m6~_KYO6eIZ+NPX!UIB7%;rkoN6Row>i6qrL;6fvn~Kl0F7Z}prHwB zY%3C{u(oE0v}^OtH=WW_V;?PhqNV#akW_02QbT=#dk>v|Qy1?P#ApD4sS4OyTm- z5HVjWvY>YA*VL+12Aczh;tdtn)_Q`I+Jpp?Pip=uMJ#TbdUj`RJ$p-22JknD_0OuN z!T51r+{zECnKcy7Jz{=&_0ju77-r?SJfoSPWUeyG!Y{QCBBH^~0EL;@o-Z$o41id9`++20{sDiE!*`Vp^d{HEogjQ1tEi5LrzBpZ`m z1F2nHfV+K$7ZYtpLJ>Qi!&pXIwKMsltBuZP);e`k3yMx?1_HrC=}Q}K6AeFr+r!IOLu*%D4&jFpEx(xmBIs{(TKV>iLWS}g3L8kb55v^7QhPW zBNVSAZgoC-4A3sLmD-izfN`nrrN>EqN2^1l^EMU9bOZT{_whu1rl`p10AsQRrDapn zd>S&+F80|l6IB#yZWfK--4xLGn+A}cC>05pCeYS6gt5X4udZ!baA`?=@d;)P9tIK5 z)bJ38S^2pYfv`rv2#6P~!g67t$jGVvunEEZ_z#$;CW74rgg}cXj&mQhMnia#DeTB= zu(hF>&Z+E_))55F^krGdTcIVVW7prn=Jk*uKrud%J)~wnnOQW`q`{wi#_s06a$)9eg0DVJ{*ESV+%MhLg)xVtHMa18M7(&BS@=y!|yt4f>Nud)87 zIrwy$pDJ7LJ*e){$YO5a(+(An@jegohn_obmjo??K)&JP^L7Jr5eq?aw(&@6cZPb} zlEuE+;KKz^R{E>FhzShJXas!Iv9m?Wnyn~A2+&s~SyNiXQAetJ2@zK9(*olxHUQf= z@Te2MCv(2=7kCmidMIAp3sQobm zpgo%3fIeAXOa2`>feoM`7IU&wGAEyHLKDbrkAZyJaS1Rc6yWW9s@U@{e6>NkF~4fh zS9nnSaqTs+Ys@cj1~gm`a7x?Isy(DRvVfjHSNVGqu5OMi2I%o^wP7;yLJK~g7nP+E zK`HEszG7+_+d_P!fR4n-ur%XhMG8u+8q4M0gaCk1cg6hM?B1g-ySmH|f~#=9{GZca ze5ivonuTR)Ij`;NcN!Q_o0}jIJ)sS<9ofECi~4sSptixmh78J2DjN=L;(VmP8iv8) zc?Xv|zbE39HC2DHH2~N-4p7525|`C{HYG#%EhxZuzbeE1fjFh*gAp_jjvcmylrl=v zTIA~I*kT~34_E52X#IbKe4AbY^KKMDQ5Qy%QCgNOWrTK4d}2 zstC*gF3%7ERo&En8U1LiBI5=`gU$#F-{y-UgqWXRzbhFQrga9@e-%Gt4A2qCut#v( z!V^@>i{&80M_@(<=!u}7icSg_bPR>-+Jc-;#yk&APw-@m^t-rAoP<+)eggZ%v1zAm z(=AmCV@>#YTLRM21}VM8MVkckr-raGA4w$u!uzo&pJiVC+-Mk(H>}ZvX#%1ZwjZO@ zV8Cb{MxrO9mEyG!W&BSb5fy#~``D;Nqjj0t*an`?%F^`H=+PpX+H~*)T->0#X;@~= zzoCsgL2f;5(4dK&UWP9+KM?7jC>tiI0qFTdrL)d|k>Ot47CE*xi_X9`OMF81%@$zv zhSmrnMkt{*9zm0#newT4Vouji+vm(fNq}q@Bmjl&hqWN}>8%F6KS&3Wxc4HN2|Yc3 zZ^kAAcgvl+@a73XsFhyP0 zkhQK&McmtT@yKp*hXBGaJY3Ws1VW1BK zMjxpD*aKkLwtd1aXevIt-k0mZt*iasfgvx>)K7Me)(27_U4&`FNB8=JZwAo>9DTNT zwNtB@-^O4bUFkP$1g`d{dHzZ{SBX{_=wiTU2yhgWAy9&W*#Q_k>`2{|Q~NRc=`Y{8hi8j~@qs|B9xNILAREXB zEs{k5YzU9oxyT@T1QS2Qe~9{|YS6Z7xOzn?wZ znF^?aDAas>v9a9Z;DeulX%kg4&lTmXmn{P#cPmVhwvC2Mx8-= zbVhr-T8`Yb+n60oEDL-1k}I2d4nuBW%_ONXZ9Bf`j37XR zU|QD%KqOq9R~VQC1Bte5CQ8I*(}W^0JP0l5d08-RRH_1WNvF0|=PN|oQAiz?(Wx?3 zq4Tn`rx7OsfRb~x!Eh%8Vd>x1h70)mTaQj}KB9UsxjFjCT5CvFgDBgI`H!|qkLBAL zV#aiGqp1&yYDiEMfezCI=-%8QEu%KJ1o^Ymq&}V!?t=5d5N{lzp~~oqa%%dFchx0)gBY;^_Gq?{{5%UClZw zM6TX@V`0Eu%6<8-(O{82<2ud>H7-2dKY&>-G}faIM=Aio4}s;BsQw_;JhCd_1!ST* zU|^x=Cxmpio7K+>12e>c_5Lc~HyD+g&$zQdi4<^ix0U81#b{vkLRY0G+NKyjB-MH`QwqE$I0v%T@!bE%{m$ z^jxJ(h7e43iEgUD*mHXNbe*Q0YNo!9?$OPeNCberi_gt5wRlvW z!IAg@goMP!cNcFzm_M~ZoXZ--q${hew4E2Y_Voc{w_sV(bB~h-C~rr3ilyPp_=Gt3 zDlhE|VM$|rDU7GqFx*X7`)Xmg(sDxI6OgIF5t@LA9QuWx_tg2-_xQT8zBr^xqEXB< z%v}QjKA0Rp*;J8ve;j^>ezz}WvVGg6GTH2aVTz^&oAX53WbdNdRQL9qv+RzWwWF*E zk{Aednc$cV3-iwn-ZytT*`@1#X8PX9Y6`UDsyluwe3DcGW>j}>G~h303o`8@pkaiT z4XblIgi10IGUqM;02_oc?S}xsV=tIuAP0~D#7b3y`T5=-P87~H6Tv^%%m%yO$dK=y z57e`dJgQH#+=kSr2QUcdTAv%`W$@#k=zpX8eQd&NK+0Ubet< zxMN`8c{c$9gd-3?Fx#R$NL80}qa?k0|1-7ht@qZm4?I%O?venI{HWG`Qa`6K|?99z$(5ptT;i`ξj9ALmcD{1 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 literal 0 HcmV?d00001 From 451736ec0e9a85c1672fc93f693812ff13d83b9f Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Wed, 19 Apr 2023 07:44:48 +0200 Subject: [PATCH 04/29] License generation --- .../Project/Sources/Classes/Standalone.4dm | 2 +- Build4D/Project/Sources/Classes/_core.4dm | 27 ++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index ef39747..8dd6c2e 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -44,7 +44,7 @@ Function build()->$success : Boolean $success:=($success) ? This._deletePaths(This.settings.deletePaths) : False $success:=($success) ? This._create4DZ() : False $success:=($success) ? This._setAppOptions() : False - $success:=($success) ? This._generateLicenses() : False + $success:=($success) ? This._generateLicense() : False If (Is macOS) $success:=($success) ? This._sign() : False End if diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index a0ee517..9d612e3 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -84,6 +84,9 @@ Function _overrideSettings($settings : Object) : ($entry.key="iconPath") This.settings.iconPath:=This._resolvePath($settings.iconPath; This._projectPackage) + : ($entry.key="license") + This.settings.license:=This._resolvePath($settings.license; Null) + : ($entry.key="sourceAppFolder") $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; Null) @@ -159,21 +162,25 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) : Object return ($absolutePath="@/") ? Folder(Folder($absolutePath; *).platformPath; fk platform path) : File(File($absolutePath; *).platformPath; fk platform path) //MARK:- -Function _checkDestinationFolder()->$result : Boolean +Function _checkDestinationFolder() : Boolean + + This._noError:=True - $result:=True - If (This.settings.destinationFolder.exists) // Delete destination folder if exists + If (This.settings.destinationFolder.exists) // Delete destination folder content if exists This.settings.destinationFolder.delete(fk recursive) End if - $result:=This.settings.destinationFolder.create() - If (Not($result)) + + If (Not(This.settings.destinationFolder.create())) This._log(New object(\ "function"; "Destination folder checking"; \ "message"; "Destination folder doesn't exist and can't be created"; \ "severity"; Error message); \ "destinationFolder"; This.settings.destinationFolder.path) + return False End if + return This._noError + //MARK:- Function _compileProject() : Boolean @@ -465,10 +472,12 @@ Function _setAppOptions() : Boolean return This._noError //MARK:- -Function _generateLicenses() : Boolean - //TODO: Licenses generation - //Create deployment license() - return True +Function _generateLicense() : Boolean + If ((This.settings.license#Null) && (This.settings.license.exists)) + $status:=Create deployment license(This.settings.destinationFolder; This.settings.license) + return $status.success + End if + //MARK:- Function _sign() : Boolean From b46ad0d490caf270bf43bad1a708e31a095932c5 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Fri, 5 May 2023 18:30:01 +0200 Subject: [PATCH 05/29] Set the lastDataPathLookup option --- Build4D/Project/Sources/Classes/_core.4dm | 65 ++++++++++++----------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 9d612e3..72fc6e2 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -426,47 +426,48 @@ Function _setAppOptions() : Boolean This._noError:=True - If (Is macOS) - - $infoFile:=This.settings.destinationFolder.file("Contents/Info.plist") + $infoFile:=(Is macOS) ? This.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") + + If ($infoFile.exists) + $appInfo:=New object(\ + "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup\ + ) - If ($infoFile.exists) - $appInfo:=New object(\ - "CFBundleDisplayName"; This.settings.buildName; \ - "CFBundleExecutable"; This.settings.buildName\ - ) - If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon + If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon + If (Is macOS) $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) + Else // Windows + $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") + If ($exeFile.exists) + If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon + $exeFile.setAppInfo(New object("WinIcon"; This.settings.iconPath)) + End if + Else + This._log(New object(\ + "function"; "Setting app options"; \ + "message"; "Exe file doesn't exist: "+$exeFile.path; \ + "severity"; Warning message)) + return False + End if End if - $infoFile.setAppInfo($appInfo) - - Else - This._log(New object(\ - "function"; "Setting app options"; \ - "message"; "Info.plist file doesn't exist: "+$infoFile.path; \ - "severity"; Warning message)) - return False End if - Else // Windows - - $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") - - If ($exeFile.exists) - - If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon - $exeFile.setAppInfo(New object("WinIcon"; This.settings.iconPath)) - End if + If (Is macOS) + $appInfo.CFBundleDisplayName:=This.settings.buildName + $appInfo.CFBundleExecutable:=This.settings.buildName + Else // Windows - Else - This._log(New object(\ - "function"; "Setting app options"; \ - "message"; "Exe file doesn't exist: "+$exeFile.path; \ - "severity"; Warning message)) - return False End if + $infoFile.setAppInfo($appInfo) + + Else + This._log(New object(\ + "function"; "Setting app options"; \ + "message"; "Info.plist file doesn't exist: "+$infoFile.path; \ + "severity"; Warning message)) + return False End if return This._noError From 96e0e2be40e1d2377132818e3e21520883e6f6c8 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Wed, 10 May 2023 20:44:43 +0200 Subject: [PATCH 06/29] Define application information --- Build4D/Project/Sources/Classes/_core.4dm | 111 ++++++++++++++++++---- Build4D/Resources/en.lproj/syntaxEN.json | 40 ++++---- 2 files changed, 113 insertions(+), 38 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 72fc6e2..2741434 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -421,8 +421,9 @@ Function _excludeModules() : Boolean //MARK:- Function _setAppOptions() : Boolean - var $appInfo : Object + var $appInfo; $exeInfo : Object var $infoFile; $exeFile : 4D.File + var $identifier : Text This._noError:=True @@ -433,35 +434,109 @@ Function _setAppOptions() : Boolean "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup\ ) + If (Is macOS) + $appInfo.CFBundleName:=This.settings.buildName + $appInfo.CFBundleDisplayName:=This.settings.buildName + $appInfo.CFBundleExecutable:=This.settings.buildName + $identifier:=((This.settings.versioning.companyName#Null) && (This.settings.versioning.companyName#"")) ? This.settings.versioning.companyName : "com.4d" + $identifier+="."+This.settings.buildName + $appInfo.CFBundleIdentifier:=$identifier + Else + $exeInfo:=New object("ProductName"; This.settings.buildName) + End if + If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon If (Is macOS) $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) Else // Windows - $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") - If ($exeFile.exists) - If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon - $exeFile.setAppInfo(New object("WinIcon"; This.settings.iconPath)) - End if - Else - This._log(New object(\ - "function"; "Setting app options"; \ - "message"; "Exe file doesn't exist: "+$exeFile.path; \ - "severity"; Warning message)) - return False - End if + $exeInfo.WinIcon:=This.settings.iconPath End if End if - If (Is macOS) - $appInfo.CFBundleDisplayName:=This.settings.buildName - $appInfo.CFBundleExecutable:=This.settings.buildName - Else // Windows - + If (This.settings.versioning#Null) // Set version info + If (Is macOS) + If (This.settings.versioning.version#Null) + $appInfo.CFBundleVersion:=This.settings.versioning.version // OK + $appInfo.CFBundleShortVersionString:=This.settings.versioning.version // OK + End if + If (This.settings.versioning.copyright#Null) + $appInfo.NSHumanReadableCopyright:=This.settings.versioning.copyright // OK + End if + //If (This.settings.versioning.creator#Null) + //$appInfo._unknown:=This.settings.versioning.creator + //End if + //If (This.settings.versioning.comment#Null) + //$appInfo.Comment:=This.settings.versioning.comment + //End if + //If (This.settings.versioning.companyName#Null) + //$appInfo.CompanyName:=This.settings.versioning.companyName + //End if + //If (This.settings.versioning.fileDescription#Null) + //$appInfo.FileDescription:=This.settings.versioning.fileDescription + //End if + //If (This.settings.versioning.internalName#Null) + //$appInfo.InternalName:=This.settings.versioning.internalName + //End if + //If (This.settings.versioning.legalTrademark#Null) + //$appInfo.LegalTrademarks:=This.settings.versioning.legalTrademark + //End if + //If (This.settings.versioning.privateBuild#Null) + //$appInfo.PrivateBuild:=This.settings.versioning.privateBuild + //End if + //If (This.settings.versioning.specialBuild#Null) + //$appInfo.SpecialBuild:=This.settings.versioning.specialBuild + //End if + + Else // Windows + If (This.settings.versioning.version#Null) + $exeInfo.ProductVersion:=This.settings.versioning.version // + End if + If (This.settings.versioning.copyright#Null) + $exeInfo.LegalCopyright:=This.settings.versioning.copyright // + End if + //If (This.settings.versioning.creator#Null) + //$exeInfo.Creator:=This.settings.versioning.creator + //End if + //If (This.settings.versioning.comment#Null) + //$exeInfo.Comment:=This.settings.versioning.comment + //End if + If (This.settings.versioning.companyName#Null) + $exeInfo.CompanyName:=This.settings.versioning.companyName + End if + If (This.settings.versioning.fileDescription#Null) + $exeInfo.FileDescription:=This.settings.versioning.fileDescription // + End if + If (This.settings.versioning.internalName#Null) + $exeInfo.InternalName:=This.settings.versioning.internalName + End if + If (This.settings.versioning.legalTrademark#Null) + $exeInfo.LegalTrademarks:=This.settings.versioning.legalTrademark // No defined in setAppInfo + End if + //If (This.settings.versioning.privateBuild#Null) + //$exeInfo.PrivateBuild:=This.settings.versioning.privateBuild + //End if + //If (This.settings.versioning.specialBuild#Null) + //$exeInfo.SpecialBuild:=This.settings.versioning.specialBuild + //End if + End if End if $infoFile.setAppInfo($appInfo) + If ($exeInfo#Null) + $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") + If ($exeFile.exists) + $exeFile.setAppInfo($exeInfo) + Else + This._log(New object(\ + "function"; "Setting app options"; \ + "message"; "Exe file doesn't exist: "+$exeFile.path; \ + "severity"; Warning message)) + return False + End if + End if + Else This._log(New object(\ "function"; "Setting app options"; \ diff --git a/Build4D/Resources/en.lproj/syntaxEN.json b/Build4D/Resources/en.lproj/syntaxEN.json index c580f29..ff4b9f2 100644 --- a/Build4D/Resources/en.lproj/syntaxEN.json +++ b/Build4D/Resources/en.lproj/syntaxEN.json @@ -14,10 +14,15 @@ "Summary": "" } }, - "Standalone": { + "_core": { "new()": { - "Syntax": "**.new**( *customSettings* : Object )", + "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", "Params": [ + [ + "target", + "Text", + "->" + ], [ "customSettings", "Object", @@ -27,15 +32,10 @@ "Summary": "" } }, - "_core": { + "Component": { "new()": { - "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", + "Syntax": "**.new**( *customSettings* : Object )", "Params": [ - [ - "target", - "Text", - "->" - ], [ "customSettings", "Object", @@ -45,7 +45,7 @@ "Summary": "" } }, - "Component": { + "Standalone": { "new()": { "Syntax": "**.new**( *customSettings* : Object )", "Params": [ @@ -73,7 +73,15 @@ }, "_inheritedFrom_": "_core" }, - "Standalone": { + "_core": { + "settings": { + "Syntax": "settings : Object" + }, + "logs": { + "Syntax": "logs : Collection" + } + }, + "Component": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ @@ -87,15 +95,7 @@ }, "_inheritedFrom_": "_core" }, - "_core": { - "logs": { - "Syntax": "logs : Collection" - }, - "settings": { - "Syntax": "settings : Object" - } - }, - "Component": { + "Standalone": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ From 25fcdee327c399b59040ef60e5d33b4f7f8c6156 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Wed, 10 May 2023 21:03:01 +0200 Subject: [PATCH 07/29] Set the SDI mode --- Build4D/Project/Sources/Classes/_core.4dm | 5 ++- Build4D/Resources/en.lproj/syntaxEN.json | 40 +++++++++++------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 2741434..0ea6600 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -431,7 +431,9 @@ Function _setAppOptions() : Boolean If ($infoFile.exists) $appInfo:=New object(\ - "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup\ + "com.4D.BuildApp.com.4D.BuildApp.ReadOnlyApp"; "True"; \ + "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup; \ + "DataFileConversionMode"; "0"\ ) If (Is macOS) @@ -442,6 +444,7 @@ Function _setAppOptions() : Boolean $identifier+="."+This.settings.buildName $appInfo.CFBundleIdentifier:=$identifier Else + $appInfo.SDIRuntime:=((This.settings.useSDI#Null) && This.settings.useSDI) ? "1" : "0" $exeInfo:=New object("ProductName"; This.settings.buildName) End if diff --git a/Build4D/Resources/en.lproj/syntaxEN.json b/Build4D/Resources/en.lproj/syntaxEN.json index ff4b9f2..c580f29 100644 --- a/Build4D/Resources/en.lproj/syntaxEN.json +++ b/Build4D/Resources/en.lproj/syntaxEN.json @@ -14,15 +14,10 @@ "Summary": "" } }, - "_core": { + "Standalone": { "new()": { - "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", + "Syntax": "**.new**( *customSettings* : Object )", "Params": [ - [ - "target", - "Text", - "->" - ], [ "customSettings", "Object", @@ -32,10 +27,15 @@ "Summary": "" } }, - "Component": { + "_core": { "new()": { - "Syntax": "**.new**( *customSettings* : Object )", + "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", "Params": [ + [ + "target", + "Text", + "->" + ], [ "customSettings", "Object", @@ -45,7 +45,7 @@ "Summary": "" } }, - "Standalone": { + "Component": { "new()": { "Syntax": "**.new**( *customSettings* : Object )", "Params": [ @@ -73,15 +73,7 @@ }, "_inheritedFrom_": "_core" }, - "_core": { - "settings": { - "Syntax": "settings : Object" - }, - "logs": { - "Syntax": "logs : Collection" - } - }, - "Component": { + "Standalone": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ @@ -95,7 +87,15 @@ }, "_inheritedFrom_": "_core" }, - "Standalone": { + "_core": { + "logs": { + "Syntax": "logs : Collection" + }, + "settings": { + "Syntax": "settings : Object" + } + }, + "Component": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ From 8d33cbf48459cf804153788aabc38f6f59378f71 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Thu, 11 May 2023 12:10:10 +0200 Subject: [PATCH 08/29] Elevate Updater privileges on Windows --- Build4D/Project/Sources/Classes/_core.4dm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 0ea6600..e25a8a6 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -422,7 +422,7 @@ Function _excludeModules() : Boolean //MARK:- Function _setAppOptions() : Boolean var $appInfo; $exeInfo : Object - var $infoFile; $exeFile : 4D.File + var $infoFile; $exeFile; $manifestFile : 4D.File var $identifier : Text This._noError:=True @@ -548,6 +548,15 @@ Function _setAppOptions() : Boolean return False End if + If (Is Windows) + $manifestFile:=((This.settings.startElevated#Null) && (This.settings.startElevated))\ + ? This.settings.destinationFolder.file("Resources/Updater/elevated.manifest")\ + : This.settings.destinationFolder.file("Resources/Updater/normal.manifest") + $manifestFile.copyTo(This.settings.destinationFolder.folder("Resources/Updater/"); "Updater.exe.manifest"; fk overwrite) + This.settings.destinationFolder.file("Resources/Updater/elevated.manifest").delete() + This.settings.destinationFolder.file("Resources/Updater/normal.manifest").delete() + End if + return This._noError //MARK:- From 1f3a6b1e98c6060f450a49f99d2e5b2bb76cb09d Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Fri, 12 May 2023 17:10:43 +0200 Subject: [PATCH 09/29] Modules exclusion --- .../Project/Sources/Classes/Standalone.4dm | 6 +-- Build4D/Project/Sources/Classes/_core.4dm | 44 +++++++++++++++++-- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index 8dd6c2e..4172f35 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -35,15 +35,15 @@ Function _renameExecutable() : Boolean Function build()->$success : Boolean $success:=This._validInstance $success:=($success) ? This._checkDestinationFolder() : False + $success:=($success) ? This._compileProject() : False + $success:=($success) ? This._createStructure() : False $success:=($success) ? This._copySourceApp() : False $success:=($success) ? This._renameExecutable() : False + $success:=($success) ? This._setAppOptions() : False $success:=($success) ? This._excludeModules() : False - $success:=($success) ? This._compileProject() : False - $success:=($success) ? This._createStructure() : False $success:=($success) ? This._includePaths(This.settings.includePaths) : False $success:=($success) ? This._deletePaths(This.settings.deletePaths) : False $success:=($success) ? This._create4DZ() : False - $success:=($success) ? This._setAppOptions() : False $success:=($success) ? This._generateLicense() : False If (Is macOS) $success:=($success) ? This._sign() : False diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index e25a8a6..631630e 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -415,9 +415,45 @@ Function _copySourceApp() : Boolean //MARK:- Function _excludeModules() : Boolean - //TODO: remove modules + var $excludedModule; $path; $basePath : Text + var $optionalModulesFile : 4D.File + var $optionalModules : Object + var $paths; $modules : Collection - return True + This._noError:=True + + If ((This.settings.excludeModules#Null) && (This.settings.excludeModules.length>0)) + $optionalModulesFile:=(Is macOS) ? Folder(Application file; fk platform path).file("Contents/Resources/BuildappOptionalModules.json") : File(Application file; fk platform path).parent.file("Resources/BuildappOptionalModules.json") + If ($optionalModulesFile.exists) + $paths:=New collection + $basePath:=(Is macOS) ? This.settings.destinationFolder.path+"Contents/" : This.settings.destinationFolder.path + $optionalModules:=JSON Parse($optionalModulesFile.getText()) + For each ($excludedModule; This.settings.excludeModules) + $modules:=$optionalModules.modules.query("name = :1"; $excludedModule) + If ($modules.length>0) + If (($modules[0].foldersArray#Null) && ($modules[0].foldersArray.length>0)) + For each ($path; $modules[0].foldersArray) + $paths.push($basePath+$path+"/") + End for each + End if + If (($modules[0].filesArray#Null) && ($modules[0].filesArray.length>0)) + For each ($path; $modules[0].filesArray) + $paths.push($basePath+$path) + End for each + End if + End if + End for each + This._deletePaths($paths) + Else + This._log(New object(\ + "function"; "Modules exclusion"; \ + "message"; "Unable to find the modules file: "+$optionalModulesFile.path; \ + "severity"; Error message)) + return False + End if + End if + + return This._noError //MARK:- Function _setAppOptions() : Boolean @@ -431,10 +467,11 @@ Function _setAppOptions() : Boolean If ($infoFile.exists) $appInfo:=New object(\ - "com.4D.BuildApp.com.4D.BuildApp.ReadOnlyApp"; "True"; \ + "com.4D.BuildApp.ReadOnlyApp"; "true"; \ "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup; \ "DataFileConversionMode"; "0"\ ) + $appInfo.SDIRuntime:=((This.settings.useSDI#Null) && This.settings.useSDI) ? "1" : "0" If (Is macOS) $appInfo.CFBundleName:=This.settings.buildName @@ -444,7 +481,6 @@ Function _setAppOptions() : Boolean $identifier+="."+This.settings.buildName $appInfo.CFBundleIdentifier:=$identifier Else - $appInfo.SDIRuntime:=((This.settings.useSDI#Null) && This.settings.useSDI) ? "1" : "0" $exeInfo:=New object("ProductName"; This.settings.buildName) End if From 03e85ae76ac617dffba987e01a1cf89741bdf938 Mon Sep 17 00:00:00 2001 From: Dev14D Date: Tue, 23 May 2023 15:11:27 +0200 Subject: [PATCH 10/29] Add doc for standalone --- Build4D/Documentation/Classes/Standalone.md | 81 +++++++++++++++++++++ Build4D/Documentation/Classes/_core.md | 71 ++++++++++++++---- 2 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 Build4D/Documentation/Classes/Standalone.md diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md new file mode 100644 index 0000000..ed8fb2d --- /dev/null +++ b/Build4D/Documentation/Classes/Standalone.md @@ -0,0 +1,81 @@ + +## Description + +This class allows you to create a standalone application. It is composed of: + +* a [Class constructor](#class-constructor) +* a [\_renameExecutable](#renameExecutable) function +* a [build()](#build) function + +### Class constructor + +```4D +Class constructor($customSettings : Object) +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in "/RESOURCES/Standalone.json" file | + +$customSettings is an object that contains the following parameters: + +| Attributes | Type | Description | +|---|---|---| +|buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| +|projectFile | File or String | Project file. Pass the project file path if you want to build an external project. Not necessary if it is a current project.| +|destinationFolder | Folder or String | Folder where the build will be generated. Defined by the component if missing in the custom settings.| +|sourceAppFolder| Folder or String | Folder of the 4D Volume Desktop.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| +|packedProject | Boolean | True if the project is compressed into a 4DZ file.| +|obfuscated | Boolean | True if the 4DZ shall not be dezippable.| +|lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName", "ByAppPath"| +|useSDI| Boolean | On Windows, use the SDI interface mode instead of the MDI.| +|startElevated| Boolean | On Windows, allow to start the Updater with elevated privileges.| +|iconPath| File or String | File of the icon to be used instead of the 4D Volume Desktop icon.| +|versioning| Object | Object contains the contents of the application information.| +|versioning.version| String | Version number | +|versioning.copyright| String | Copyright text | +|versioning.creator| String | Creator code (4 characters maximum) (macOS only)| +|versioning.comment| String | Comment (Windows only) | +|versioning.companyName| String | Company name (Windows only)| +|versioning.fileDescription| String | Description (Windows only)| +|versioning.internalName| String | Internal name (Windows only)| +|includePaths[] | Collection of Objects | Collection of folders and files to include.| +|includePaths[].source | String | Source folder or file path (relative to the built project/absolute/filesystem strings).| +|includePaths[].destination | String | Destination folder path (relative to the built project/absolute/filesystem strings).| +|deletePaths[] | Collection of Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| +|excludeModules| Collection of Strings | Collection of module names to exclude from final application. The module names can be found in the "BuildappOptionalModules.json" file in the resources of 4D application.| +|license| File or String | Unlimited desktop license file.| +|signApplication.macSignature | Boolean | Signs the built applications.| +|signApplication.macCertificate | String | Certificate name used for signature.| +|signApplication.adHocSignature | Boolean | Signs the built applications with AdHoc signature if macSignature not performed.| +|logger | Formula | Formula called when a log is written.| + +

_renameExecutable

+ +```4D +Function _renameExecutable() -> $status : Boolean +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $status | Boolean | out | True if the executable has correctly renamed. | + +Rename the executable. + +### build() + +```4D +Function build() -> $status : Boolean +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $status | Boolean | out | True if the standalone has been correctly executed| + +Build the standalone application. + +## Example + +```4D + + + +``` diff --git a/Build4D/Documentation/Classes/_core.md b/Build4D/Documentation/Classes/_core.md index 34ccdc4..18ac3d2 100644 --- a/Build4D/Documentation/Classes/_core.md +++ b/Build4D/Documentation/Classes/_core.md @@ -5,15 +5,18 @@ This class is a base class used by the other classes to create a compiled projec * [Class constructor](#class-constructor) * [Function \_checkDestinationFolder](#function-checkDestinationFolder) -* [Function \_checkSettings](#function-checkSettings) * [Function \_compileProject](#function-compileProject) +* [Function \_copySourceApp](#function-copySourceApp) * [Function \_create4DZ](#function-create4DZ) * [Function \_createStructure](#function-createStructure) * [Function \_deletePaths](#function-deletePaths) +* [Function \_excludeModules](#function-excludeModules) +* [Function \_generateLicense](#function-generateLicense) * [Function \_includePaths](#function-includePaths) * [Function \_log](#function-log) * [Function \_overrideSettings](#function-overrideSettings) * [Function \_resolvePath()](#function-resolvePath) +* [Function \_setAppOptions()](#function-setAppOptions) * [Function \_sign()](#function-sign) ### Class constructor @@ -31,10 +34,11 @@ $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| |\_validInstance | Boolean | True if the instanciated object can be used for build. False if a condition is not filled (e.g. project doesn't exist).| -|\_projectFile | File | Project file| +|\_projectFile | File | Project file.| |\_projectPackage | Folder | Folder of the project package.| |\_isCurrentProject | Boolean | True if the project is the current one.| |\_isDefaultDestinationFolder | Boolean | True if the destination folder is the one computed automatically.| +|\_structureFolder | Folder | Folder of the destination structure.| |settings | Object | Root object containing all settings for target build. Can be overriden by a constructor's parameter. The structure of the $settings object is described in each class corresponding to the target.|

Function _checkDestinationFolder

@@ -48,26 +52,28 @@ Function _checkDestinationFolder() -> $status : Boolean Checks the destination folder. -

Function _checkSettings

+

Function _compileProject

```4D -Function _checkSettings($settings : Collection) -> $status : Boolean +Function _compileProject() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $parameters | Collection | in | | -| $status | Boolean | out | | +| $status | Boolean | out | True if the compilation has succeeded. If not, the compilation's result object is included in an error log. | -

Function _compileProject

+Compiles the project, with the settings.compilerOptions if exists. + +

Function _copySourceApp

```4D -Function _compileProject() -> $status : Boolean +Function _copySourceApp() -> $status : Boolean ``` + | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the compilation has succeeded. If not, the compilation's result object is included in an error log. | +| $status | Boolean | out | True if the copy is successful. | -Compiles the project, with the settings.compilerOptions if exists. +Copy the source application (4D Volume Desktop or 4D Server) in the destination folder.

Function _create4DZ

@@ -96,7 +102,6 @@ Creates the destination structure folders and files. ```4D Function _deletePaths($paths : Collection) -> $status : Boolean ``` - | Parameter | Type | in/out | Description | |---|---|---|---| | $paths | Collection of texts | in | List of folders and files to delete | @@ -104,12 +109,33 @@ Function _deletePaths($paths : Collection) -> $status : Boolean Deletes folders and files from the destination structure. +

Function _excludeModules

+ +```4D +Function _excludeModules() -> $status : Boolean +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $status | Boolean | out | True if all modules have been correctly removed. If not, an error log is created with "path" information.| + +Deletes the folders and files composing the module to be removed according to the information in the "/RESOURCES/BuildappOptionalModules.json" file + +

Function _generateLicense

+ +```4D +Function _generateLicense() -> $status : Boolean +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $status | Boolean | out | True if the deployment license have been correctly created. If not, xxx.| + +Create the deployment license file in the license folder of the generated application. +

Function _includePaths

```4D Function _includePaths($pathsObj : Collection) -> $status : Boolean ``` - | Parameter | Type | in/out | Description | |---|---|---|---| | $paths | Collection of objects | in | List of folder and file objects to include | @@ -124,7 +150,9 @@ Function _log($log : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $log | Object | in | | +| $log | Object | in | $log contains attributes "function", "message", "messageSeverity" and optionnaly "result", "path", "sourcePath", "destinationPath". | + +Calls the settings.formulaForLogs formula with $log object parameter.

Function _overrideSettings

@@ -133,7 +161,7 @@ Function _overrideSettings($settings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $settings | Object | in | | +| $settings | Object | in | Settings passed by the derived class to override the default settings | Overrides the default target settings with the $settings parameter. @@ -144,12 +172,23 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) -> $object : Object ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $path | Text | in | | -| $baseFolder | 4D.Folder | in | | +| $path | Text | in | Relative path to $baseFolder | +| $baseFolder | 4D.Folder | in | Absolute path | | $object | 4D.Folder or 4D.File | out | Return a 4D folder or 4D File | Resolves a relative/absolute/filesystem string path to Folder/File object. +

Function _setAppOptions

+ +```4D +Function _setAppOptions()-> $status : Boolean +``` +| Parameter | Type | in/out | Description | +|---|---|---|---| +| $status | Boolean | out | True if the information has been correctly added. | + +Set information to the application. +

Function _sign

```4D From 5ab2d7fd425b2052158754e5ae0e92bfd08e0f69 Mon Sep 17 00:00:00 2001 From: Dev14D Date: Thu, 25 May 2023 16:38:28 +0200 Subject: [PATCH 11/29] Update readme and add example --- Build4D/Documentation/Classes/Standalone.md | 63 +++++++++++++++++++-- README.md | 3 +- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index ed8fb2d..f8c03df 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -30,7 +30,7 @@ $customSettings is an object that contains the following parameters: |lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName", "ByAppPath"| |useSDI| Boolean | On Windows, use the SDI interface mode instead of the MDI.| |startElevated| Boolean | On Windows, allow to start the Updater with elevated privileges.| -|iconPath| File or String | File of the icon to be used instead of the 4D Volume Desktop icon.| +|iconPath| File or String | File path of the icon to be used instead of the 4D Volume Desktop icon.| |versioning| Object | Object contains the contents of the application information.| |versioning.version| String | Version number | |versioning.copyright| String | Copyright text | @@ -74,8 +74,63 @@ Build the standalone application. ## Example -```4D - - +This code is an example to generate a standalone application from an external project. +```4D +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean + +$settings:=New object() + +// Define external project file +$settings.projectFile:=Folder(fk documents folder).file("Contact/Project/Contact.4DProject") + +// Configure the application +$settings.buildName:="myApp" +$settings.destinationFolder:="Test/" +$settings.obfuscated:=True +$settings.packedProject:=False +$settings.useSDI:=False +$settings.startElevated:=False +$settings.lastDataPathLookup:="ByAppPath" + +// Define 4D Volume Desktop path +$settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app").path + +// Delete unneccessary module +$settings.excludeModules:=New collection("CEF"; "MeCab") + +// Include folders and files +$settings.includePaths:=New collection +$settings.includePaths.push(New object("source"; "Documentation/")) + +// Delete folders and files +$settings.deletePaths:=New collection +$settings.deletePaths.push("Resources/Dev/") + +// Add the application icon +$settings.iconPath:="/RESOURCES/myIcon.icns" + +// Add the application information +$settings.versioning:=New object +$settings.versioning.version:="myBuild4D_version" +$settings.versioning.copyright:="myBuild4D_copyright" +$settings.versioning.creator:="myBuild4D_creator" +$settings.versioning.comment:="myBuild4D_comment" +$settings.versioning.companyName:="myBuild4D_companyName" +$settings.versioning.fileDescription:="myBuild4D_fileDescription" +$settings.versioning.internalName:="myBuild4D_internalName" + +// Create the deployment license file +$settings.license:=Folder(fk licenses folder).file("XXXXX.license4D").path + +// Sign the macOS appplication +$settings.signApplication:=New object +$settings.signApplication.macSignature:=True +$settings.signApplication.macCertificate:="xxxxxx" + +// Launch build +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() ``` diff --git a/README.md b/README.md index 8374747..c4ea3b6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Welcome to Build4D! This 4D project allows you to compile, build and sign: * compiled projects * components -* standalone applications (planned) +* standalone applications * server applications (planned) * client applications (planned) @@ -15,4 +15,5 @@ Several classes are available. For more details, please refer to the class docum * [CompiledProject](./Build4D/Documentation/Classes/CompiledProject.md) * [Component](./Build4D/Documentation/Classes/Component.md) +* [Standalone](./Build4D/Documentation/Classes/Standalone.md) * [_core](./Build4D/Documentation/Classes/_core.md) From f4517e22a63cc5866f89b422ffc824086023259d Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Wed, 7 Jun 2023 19:53:09 +0200 Subject: [PATCH 12/29] Bug fixes #11887 #11912 #11960 #11962 #11964 --- Build4D/Project/Sources/Classes/_core.4dm | 64 ++++++++++++++++++----- Build4D/Resources/en.lproj/syntaxEN.json | 40 +++++++------- Build4D/Settings/buildApp.4DSettings | 33 ++++-------- 3 files changed, 82 insertions(+), 55 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 631630e..d9f6807 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -154,7 +154,7 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) : Object var $pathExists : Boolean $pathExists:=($path="@/") ? Folder(Folder($path; *).platformPath; fk platform path).exists : File(File($path; *).platformPath; fk platform path).exists - $absolutePath:=($pathExists) ? $path : $absoluteFolder.path+$path + $absolutePath:=($pathExists) ? $path : Choose($baseFolder#Null; $absoluteFolder.path; "")+$path End case End case @@ -468,7 +468,7 @@ Function _setAppOptions() : Boolean If ($infoFile.exists) $appInfo:=New object(\ "com.4D.BuildApp.ReadOnlyApp"; "true"; \ - "com.4D.BuildApp.LastDataPathLookup"; This.settings.lastDataPathLookup; \ + "com.4D.BuildApp.LastDataPathLookup"; Choose((This.settings.lastDataPathLookup="ByAppName") | (This.settings.lastDataPathLookup="ByAppPath"); This.settings.lastDataPathLookup; "ByAppName"); \ "DataFileConversionMode"; "0"\ ) $appInfo.SDIRuntime:=((This.settings.useSDI#Null) && This.settings.useSDI) ? "1" : "0" @@ -484,23 +484,47 @@ Function _setAppOptions() : Boolean $exeInfo:=New object("ProductName"; This.settings.buildName) End if - If ((This.settings.iconPath#Null) && (This.settings.iconPath.exists)) // Set icon - If (Is macOS) - $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName - This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) - Else // Windows - $exeInfo.WinIcon:=This.settings.iconPath + If (This.settings.iconPath#Null) // Set icon + If (This.settings.iconPath.exists) + If (Is macOS) + $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName + This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) + Else // Windows + $exeInfo.WinIcon:=This.settings.iconPath + End if + Else + This._log(New object(\ + "function"; "Icon integration"; \ + "message"; "Icon file doesn't exist: "+This.settings.iconPath.path; \ + "severity"; Error message)) End if End if If (This.settings.versioning#Null) // Set version info If (Is macOS) If (This.settings.versioning.version#Null) - $appInfo.CFBundleVersion:=This.settings.versioning.version // OK - $appInfo.CFBundleShortVersionString:=This.settings.versioning.version // OK + $appInfo.CFBundleVersion:=This.settings.versioning.version + $appInfo.CFBundleShortVersionString:=This.settings.versioning.version End if If (This.settings.versioning.copyright#Null) - $appInfo.NSHumanReadableCopyright:=This.settings.versioning.copyright // OK + $appInfo.NSHumanReadableCopyright:=This.settings.versioning.copyright + // Force macOS to get copyright from info.plist file instead of localized strings file + var $subFolder : 4D.Folder + var $infoPlistFile : 4D.File + var $resourcesSubFolders : Collection + var $fileContent : Text + $resourcesSubFolders:=This.settings.destinationFolder.folder("Contents/Resources/").folders() + For each ($subFolder; $resourcesSubFolders) + If ($subFolder.extension=".lproj") + $infoPlistFile:=$subFolder.file("InfoPlist.strings") + If ($infoPlistFile.exists) + $fileContent:=$infoPlistFile.getText() + $fileContent:=Replace string($fileContent; "CFBundleGetInfoString ="; "CF4DBundleGetInfoString ="; 1) + $fileContent:=Replace string($fileContent; "NSHumanReadableCopyright ="; "NS4DHumanReadableCopyright ="; 1) + $infoPlistFile.setText($fileContent) + End if + End if + End for each End if //If (This.settings.versioning.creator#Null) //$appInfo._unknown:=This.settings.versioning.creator @@ -597,12 +621,26 @@ Function _setAppOptions() : Boolean //MARK:- Function _generateLicense() : Boolean + var $status : Object + If ((This.settings.license#Null) && (This.settings.license.exists)) $status:=Create deployment license(This.settings.destinationFolder; This.settings.license) - return $status.success + If ($status.success) + return True + Else + This._log(New object(\ + "function"; "Deployment license creation"; \ + "message"; "Deployment license creation failed"; \ + "severity"; Error message; \ + "result"; $status)) + End if + Else + This._log(New object(\ + "function"; "Deployment license creation"; \ + "message"; "License file doesn't exist: "+Choose(This.settings.license#Null; This.settings.license.path; "Undefined"); \ + "severity"; Error message)) End if - //MARK:- Function _sign() : Boolean diff --git a/Build4D/Resources/en.lproj/syntaxEN.json b/Build4D/Resources/en.lproj/syntaxEN.json index c580f29..ff4b9f2 100644 --- a/Build4D/Resources/en.lproj/syntaxEN.json +++ b/Build4D/Resources/en.lproj/syntaxEN.json @@ -14,10 +14,15 @@ "Summary": "" } }, - "Standalone": { + "_core": { "new()": { - "Syntax": "**.new**( *customSettings* : Object )", + "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", "Params": [ + [ + "target", + "Text", + "->" + ], [ "customSettings", "Object", @@ -27,15 +32,10 @@ "Summary": "" } }, - "_core": { + "Component": { "new()": { - "Syntax": "**.new**( *target* : Text; *customSettings* : Object )", + "Syntax": "**.new**( *customSettings* : Object )", "Params": [ - [ - "target", - "Text", - "->" - ], [ "customSettings", "Object", @@ -45,7 +45,7 @@ "Summary": "" } }, - "Component": { + "Standalone": { "new()": { "Syntax": "**.new**( *customSettings* : Object )", "Params": [ @@ -73,7 +73,15 @@ }, "_inheritedFrom_": "_core" }, - "Standalone": { + "_core": { + "settings": { + "Syntax": "settings : Object" + }, + "logs": { + "Syntax": "logs : Collection" + } + }, + "Component": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ @@ -87,15 +95,7 @@ }, "_inheritedFrom_": "_core" }, - "_core": { - "logs": { - "Syntax": "logs : Collection" - }, - "settings": { - "Syntax": "settings : Object" - } - }, - "Component": { + "Standalone": { "build()": { "Syntax": "**.build**()->success : Boolean", "Params": [ diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index 5cdb32b..66ac8db 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -2,9 +2,9 @@ - True + False True - True + False True ByAppPath @@ -14,17 +14,17 @@ True Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: C:\Program Files\4D\4D v0.0\4D Volume Desktop\ + Z:\4D\GitHub\Build4D\Build4D_UnitTests\Build4D.ico + ::Build4D_UnitTests:Build4D.icns - True - True + False False - Macintosh HD:Applications:4D v0.0:4D Server.app: - Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: + False - True - ByAppPath + False + ByAppName False False @@ -33,7 +33,7 @@ Build4D - ::Test: + ..\Test\ 0 @@ -47,26 +47,15 @@ 0 - - 3 - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4UUD200UUS0018PNC005EC7.license4D - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4DTD200UUS001APL85125DE.license4D - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4DDP200UUS001APL8416796.license4D - - 2 + 1 C:\ProgramData\4D\Licenses\R-4UUD200UUS0018PNC005EC7.license4D - C:\ProgramData\4D\Licenses\R-4DDP200UUS001APL8416796.license4D +
False - True - Z:\4D\GitHub\Build4D\Test\Legacy\win\ - - - From 4e57d5edb52f650d26c873c19850ff7374fd58fb Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Thu, 8 Jun 2023 18:10:07 +0200 Subject: [PATCH 13/29] Bug fixes #11963 Relative path for project file outside the current package project --- Build4D/Project/Sources/Classes/_core.4dm | 3 ++- Build4D/Settings/buildApp.4DSettings | 6 +++--- .../Build4D_External/Project/Sources/catalog.4DCatalog | 2 +- .../Project/Sources/Methods/ut_R3490_TC5331.4dm | 2 +- .../Project/Sources/Methods/ut_R3490_TC5333.4dm | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index d9f6807..446ebad 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -26,7 +26,7 @@ Class constructor($target : Text; $customSettings : Object) This._projectFile:=File(Structure file(*); fk platform path) If (($settings#Null) && ($settings.projectFile#Null) && ($settings.projectFile#"")) This._isCurrentProject:=False - This._projectFile:=This._resolvePath($settings.projectFile; Folder("/PACKAGE/"; *)) + This._projectFile:=This._resolvePath($settings.projectFile; Folder(Folder("/PACKAGE/"; *).platformPath; fk platform path)) If (Not(This._projectFile.exists)) This._validInstance:=False This._log(New object(\ @@ -489,6 +489,7 @@ Function _setAppOptions() : Boolean If (Is macOS) $appInfo.CFBundleIconFile:=This.settings.iconPath.fullName This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/")) + This.settings.iconPath.copyTo(This.settings.destinationFolder.folder("Contents/Resources/Images/WindowIcons/"); "windowIcon_205.icns"; fk overwrite) Else // Windows $exeInfo.WinIcon:=This.settings.iconPath End if diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index 66ac8db..d621eda 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -1,6 +1,5 @@ - False True @@ -13,9 +12,10 @@ True Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: - C:\Program Files\4D\4D v0.0\4D Volume Desktop\ - Z:\4D\GitHub\Build4D\Build4D_UnitTests\Build4D.ico + C:\Program Files\4D\4D v0.0\4D Volume Desktop\ + ..\Build4D_UnitTests\Build4D.ico ::Build4D_UnitTests:Build4D.icns + False False diff --git a/Build4D_UnitTests/Build4D_External/Project/Sources/catalog.4DCatalog b/Build4D_UnitTests/Build4D_External/Project/Sources/catalog.4DCatalog index f1fcf12..1d7f73b 100644 --- a/Build4D_UnitTests/Build4D_External/Project/Sources/catalog.4DCatalog +++ b/Build4D_UnitTests/Build4D_External/Project/Sources/catalog.4DCatalog @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm index dbef6df..5f63dca 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm +++ b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm @@ -2,7 +2,7 @@ // Compile an application/component with good $settings.compilerOptions var $build : cs.Build4D.CompiledProject var $settings : Object -var $success : Boolean +var $success : Variant var $link : Text $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm index 2bd3af0..d3c5cdf 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm +++ b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm @@ -2,7 +2,7 @@ // Compile an application/component with wrong $settings.compilerOptions var $build : cs.Build4D.CompiledProject var $settings : Object -var $success : Boolean +var $success : Variant var $link : Text $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" From 4ea1673ccd6b443aa3e1aedcad31404a47f77f64 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Thu, 8 Jun 2023 20:20:32 +0200 Subject: [PATCH 14/29] All file/folder parameters can use File/Folder object or string paths as well --- Build4D/Project/Sources/Classes/_core.4dm | 141 +++++++++--------- Build4D/Settings/buildApp.4DSettings | 8 +- .../Project/Sources/Methods/onStartup.4dm | 14 +- 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 446ebad..3de7fed 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -1,6 +1,6 @@ property _validInstance; _isCurrentProject; _isDefaultDestinationFolder; _noError : Boolean property _projectFile : 4D.File -property _projectPackage; _structureFolder : 4D.Folder +property _currentProjectPackage; _projectPackage; _structureFolder : 4D.Folder property logs : Collection property settings : Object @@ -24,7 +24,10 @@ Class constructor($target : Text; $customSettings : Object) This._validInstance:=True This._isCurrentProject:=True This._projectFile:=File(Structure file(*); fk platform path) - If (($settings#Null) && ($settings.projectFile#Null) && ($settings.projectFile#"")) + This._currentProjectPackage:=This._projectFile.parent.parent + If (($settings#Null) && ($settings.projectFile#Null) && \ + ((Value type($settings.projectFile)=Is object) && OB Instance of($settings.projectFile; 4D.File)) || \ + ((Value type($settings.projectFile)=Is text) && ($settings.projectFile#""))) This._isCurrentProject:=False This._projectFile:=This._resolvePath($settings.projectFile; Folder(Folder("/PACKAGE/"; *).platformPath; fk platform path)) If (Not(This._projectFile.exists)) @@ -82,13 +85,15 @@ Function _overrideSettings($settings : Object) This.settings.includePaths:=This.settings.includePaths.concat($settings.includePaths) : ($entry.key="iconPath") - This.settings.iconPath:=This._resolvePath($settings.iconPath; This._projectPackage) + This.settings.iconPath:=This._resolvePath($settings.iconPath; This._currentProjectPackage) : ($entry.key="license") This.settings.license:=This._resolvePath($settings.license; Null) : ($entry.key="sourceAppFolder") - $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" + If (Value type($settings.sourceAppFolder)=Is text) + $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" + End if This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; Null) If ((This.settings.sourceAppFolder=Null) || (Not(OB Instance of(This.settings.sourceAppFolder; 4D.Folder)) || (Not(This.settings.sourceAppFolder.exists)))) This._validInstance:=False @@ -125,42 +130,51 @@ Function _log($log : Object) End if //MARK:- -Function _resolvePath($path : Text; $baseFolder : 4D.Folder) : Object - - var $absolutePath : Text - var $absoluteFolder; $app : 4D.Folder +Function _resolvePath($path : Variant; $baseFolder : 4D.Folder) : Object - $absoluteFolder:=$baseFolder Case of - : ($path="./@") // Relative path inside $baseFolder - $path:=Substring($path; 3) - $absolutePath:=$absoluteFolder.path+$path - : ($path="../@") // Relative path outside $baseFolder - While ($path="../@") - $absoluteFolder:=$absoluteFolder.parent - $path:=Substring($path; 4) - End while - $absolutePath:=$absoluteFolder.path+$path - Else // Absolute path or custom fileSystem + : ((Value type($path)=Is object) && (OB Instance of($path; 4D.File) || OB Instance of($path; 4D.Folder))) // $path is a File or a Folder + return $path + + : (Value type($path)=Is text) // $path is a text + var $absolutePath : Text + var $absoluteFolder; $app : 4D.Folder + + $absoluteFolder:=$baseFolder Case of - : ($path="/4DCOMPONENTS/@") - $app:=(Is macOS) ? Folder(Application file; fk platform path).folder("Contents/Components") : File(Application file; fk platform path).parent.folder("Components") - $absolutePath:=$app.path+Substring($path; 15) - - : (($path="") | ($path="/")) // Base folder - $absolutePath:=$baseFolder.path - - Else // Absolute path or baseFolder subpath + : ($path="./@") // Relative path inside $baseFolder + $path:=Substring($path; 3) + $absolutePath:=$absoluteFolder.path+$path + : ($path="../@") // Relative path outside $baseFolder + While ($path="../@") + $absoluteFolder:=$absoluteFolder.parent + $path:=Substring($path; 4) + End while + $absolutePath:=$absoluteFolder.path+$path + Else // Absolute path or custom fileSystem + Case of + : ($path="/4DCOMPONENTS/@") + $app:=(Is macOS) ? Folder(Application file; fk platform path).folder("Contents/Components") : File(Application file; fk platform path).parent.folder("Components") + $absolutePath:=$app.path+Substring($path; 15) + + : (($path="") | ($path="/")) // Base folder + $absolutePath:=$baseFolder.path + + Else // Absolute path or baseFolder subpath + + var $pathExists : Boolean + $pathExists:=($path="@/") ? Folder(Folder($path; *).platformPath; fk platform path).exists : File(File($path; *).platformPath; fk platform path).exists + $absolutePath:=($pathExists) ? $path : Choose($baseFolder#Null; $absoluteFolder.path; "")+$path + End case - var $pathExists : Boolean - $pathExists:=($path="@/") ? Folder(Folder($path; *).platformPath; fk platform path).exists : File(File($path; *).platformPath; fk platform path).exists - $absolutePath:=($pathExists) ? $path : Choose($baseFolder#Null; $absoluteFolder.path; "")+$path End case + return ($absolutePath="@/") ? Folder(Folder($absolutePath; *).platformPath; fk platform path) : File(File($absolutePath; *).platformPath; fk platform path) + + Else + return Null End case - return ($absolutePath="@/") ? Folder(Folder($absolutePath; *).platformPath; fk platform path) : File(File($absolutePath; *).platformPath; fk platform path) - //MARK:- Function _checkDestinationFolder() : Boolean @@ -264,35 +278,29 @@ Function _includePaths($pathsObj : Collection) : Boolean "severity"; Error message)) return False Else - Case of - : (Value type($pathObj.source)=Is text) - $sourcePath:=This._resolvePath($pathObj.source; This._projectPackage) - : ((OB Instance of($pathObj.source; 4D.Folder)) || (OB Instance of($pathObj.source; 4D.File))) - $sourcePath:=$pathObj.source - Else - This._log(New object(\ - "function"; "Paths include"; \ - "message"; "Collection.source must contain Posix text paths, 4D.File objects or 4D.Folder objects"; \ - "severity"; Error message)) - return False - End case + If ((Value type($pathObj.source)=Is text) || (OB Instance of($pathObj.source; 4D.Folder)) || (OB Instance of($pathObj.source; 4D.File))) + $sourcePath:=This._resolvePath($pathObj.source; This._currentProjectPackage) + Else + This._log(New object(\ + "function"; "Paths include"; \ + "message"; "Collection.source must contain Posix text paths, 4D.File objects or 4D.Folder objects"; \ + "severity"; Error message)) + return False + End if End if If (Undefined($pathObj.destination)) $destinationPath:=This._structureFolder Else - Case of - : (Value type($pathObj.destination)=Is text) - $destinationPath:=This._resolvePath($pathObj.destination; This._structureFolder) - : (OB Instance of($pathObj.destination; 4D.Folder)) - $destinationPath:=$pathObj.destination - Else - This._log(New object(\ - "function"; "Paths include"; \ - "message"; "Collection.destination must contain Posix text paths or 4D.Folder objects"; \ - "severity"; Error message)) - return False - End case + If ((Value type($pathObj.destination)=Is text) || (OB Instance of($pathObj.destination; 4D.Folder))) + $destinationPath:=This._resolvePath($pathObj.destination; This._structureFolder) + Else + This._log(New object(\ + "function"; "Paths include"; \ + "message"; "Collection.destination must contain Posix text paths or 4D.Folder objects"; \ + "severity"; Error message)) + return False + End if End if If (Not($destinationPath.exists) && Not($destinationPath.create())) @@ -346,18 +354,15 @@ Function _deletePaths($paths : Collection) : Boolean If (($paths#Null) && ($paths.length>0)) For each ($path; $paths) - Case of - : (Value type($path)=Is text) - $deletePath:=This._resolvePath($path; This._structureFolder) - : ((OB Instance of($path; 4D.Folder)) || (OB Instance of($path; 4D.File))) - $deletePath:=$path - Else - This._log(New object(\ - "function"; "Paths delete"; \ - "message"; "Collection must contain Posix text paths, 4D.File objects or 4D.Folder objects"; \ - "severity"; Error message)) - return False - End case + If ((Value type($path)=Is text) || ((OB Instance of($path; 4D.Folder)) || (OB Instance of($path; 4D.File)))) + $deletePath:=This._resolvePath($path; This._structureFolder) + Else + This._log(New object(\ + "function"; "Paths delete"; \ + "message"; "Collection must contain Posix text paths, 4D.File objects or 4D.Folder objects"; \ + "severity"; Error message)) + return False + End if If ($deletePath.exists) $deletePath.delete(fk recursive) diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings index d621eda..2cd94f8 100644 --- a/Build4D/Settings/buildApp.4DSettings +++ b/Build4D/Settings/buildApp.4DSettings @@ -51,11 +51,17 @@ 1 C:\ProgramData\4D\Licenses\R-4UUD200UUS0018PNC005EC7.license4D + + 1 + Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4UUD200UUS0018PNC005EC7.license4D + False - + True + ::Build4D_Build + diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm index fd5304f..bb83217 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm +++ b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm @@ -9,19 +9,19 @@ If (Count parameters=0) // Execute code in a new worker Use (Storage) Storage.settings:=New shared object("rootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path)) //"projectName"; File(Structure file(*); fk platform path).name; \ - "externalRootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path).parent.folder("Build4D_External"); \ - "externalProjectName"; ""; \ - "userInterface"; Not(Get application info.headless); \ - "logRunFile"; File($rootFolder+"UT_run.log").path; \ - "logErrorFile"; File($rootFolder+"UT_errors.log").path\ - ) + "externalRootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path).parent.folder("Build4D_External"); \ + "externalProjectName"; ""; \ + "userInterface"; Not(Get application info.headless); \ + "logRunFile"; File($rootFolder+"UT_run.log").path; \ + "logErrorFile"; File($rootFolder+"UT_errors.log").path\ + ) End use Use (Storage.settings) Storage.settings.projectName:=File(Structure file(*); fk platform path).name Storage.settings.userInterface:=Not(Get application info.headless) Storage.settings.externalProjectRootFolder:=Storage.settings.rootFolder.parent.folder("Build4D_External") Storage.settings.externalProjectName:="Build4D_External" - Storage.settings.externalProjectFile:=Storage.settings.externalProjectRootFolder.path+"Project/Build4D_External.4DProject" + Storage.settings.externalProjectFile:=Storage.settings.externalProjectRootFolder.file("Project/Build4D_External.4DProject") Storage.settings.logRunFile:=Storage.settings.rootFolder.file("UT_run.log") Storage.settings.logErrorFile:=Storage.settings.rootFolder.file("UT_errors.log") End use From 10ddbe05b933d7145eef01e9bed79965d95af5c9 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Fri, 9 Jun 2023 11:04:45 +0200 Subject: [PATCH 15/29] Delete buildApp.4DSettings --- Build4D/Settings/buildApp.4DSettings | 67 ---------------------------- 1 file changed, 67 deletions(-) delete mode 100644 Build4D/Settings/buildApp.4DSettings diff --git a/Build4D/Settings/buildApp.4DSettings b/Build4D/Settings/buildApp.4DSettings deleted file mode 100644 index 2cd94f8..0000000 --- a/Build4D/Settings/buildApp.4DSettings +++ /dev/null @@ -1,67 +0,0 @@ - - - - False - True - False - True - - ByAppPath - - - - True - Macintosh HD:Applications:4D v0.0:4D Volume Desktop.app: - C:\Program Files\4D\4D v0.0\4D Volume Desktop\ - ..\Build4D_UnitTests\Build4D.ico - ::Build4D_UnitTests:Build4D.icns - - - False - False - False - - - - False - ByAppName - False - - False - False - 1 - - - Build4D - ..\Test\ - - 0 - - - 0 - - - 0 - - - 0 - - - - 1 - C:\ProgramData\4D\Licenses\R-4UUD200UUS0018PNC005EC7.license4D - - - 1 - Macintosh HD:Users:Damien:Library:Application Support:4D:Licenses:R-4UUD200UUS0018PNC005EC7.license4D - - - - False - - True - ::Build4D_Build - - - - From c3af372668004b093f9d4fa5a35197632acac4e6 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Fri, 9 Jun 2023 18:21:05 +0200 Subject: [PATCH 16/29] Base path changes + corresponding UTs + TU folder refactoring --- .gitignore | 2 +- Build4D/Project/Sources/Classes/_core.4dm | 51 ++-------- .../Project/Sources/folders.json | 87 ------------------ .../Documentation/Methods/onStartup.md | 0 .../Project/Build4D_UnitTests.4DProject | 0 .../Sources/DatabaseMethods/onStartup.4dm | 0 .../Sources/Methods/compilationError.4dm | 0 .../Sources/Methods/compilationTest.4dm | 2 + .../Sources/Methods/compilerMethods.4dm | 0 .../Sources/Methods/logGitHubActions.4dm | 0 .../Sources/Methods/mut_2_R3486_TC4743.4dm} | 0 .../Sources/Methods/mut_2_R3486_TC4749.4dm} | 0 .../Project/Sources/Methods/onError.4dm | 0 .../Project/Sources/Methods/onStartup.4dm | 14 +-- .../Sources/Methods/runAutomaticUnitTests.4dm | 43 +++++---- .../Sources/Methods/runManualUnitTests.4dm | 0 .../Project/Sources/Methods/runUnitTests1.4dm | 47 ++++++++++ .../Project/Sources/Methods/runUnitTests2.4dm | 47 ++++++++++ .../Project/Sources/Methods/runUnitTests3.4dm | 47 ++++++++++ .../Sources/Methods/ut_1_R3485_TC4734.4dm} | 5 +- .../Sources/Methods/ut_1_R3485_TC4736.4dm} | 3 +- .../Sources/Methods/ut_1_R3485_TC6022.4dm} | 4 +- .../Sources/Methods/ut_1_R3485_TC6023.4dm} | 4 +- .../Sources/Methods/ut_1_R3489_TC5319.4dm} | 2 +- .../Sources/Methods/ut_1_R3489_TC5321.4dm} | 2 +- .../Sources/Methods/ut_1_R3489_TC5322.4dm} | 2 +- .../Sources/Methods/ut_1_R3490_TC5331.4dm} | 0 .../Sources/Methods/ut_1_R3490_TC5333.4dm} | 0 .../Sources/Methods/ut_1_R3491_TC5334.4dm} | 2 +- .../Sources/Methods/ut_1_R3491_TC5336.4dm} | 2 +- .../Sources/Methods/ut_1_R3491_TC5337.4dm} | 2 +- .../Sources/Methods/ut_2_R3484_TC4725.4dm} | 3 +- .../Sources/Methods/ut_2_R3484_TC4732.4dm} | 0 .../Sources/Methods/ut_2_R3484_TC4733.4dm} | 0 .../Sources/Methods/ut_2_R3486_TC4737.4dm} | 0 .../Sources/Methods/ut_2_R3486_TC4739.4dm} | 2 +- .../Sources/Methods/ut_2_R3486_TC4741.4dm} | 2 +- .../Sources/Methods/ut_2_R3486_TC4745.4dm} | 2 +- .../Sources/Methods/ut_2_R3486_TC4746.4dm} | 2 +- .../Sources/Methods/ut_2_R3486_TC4747.4dm} | 2 +- .../Sources/Methods/ut_2_R3486_TC4750.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC5165.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC5167.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC5169.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC5170.4dm} | 0 .../Sources/Methods/ut_2_R3487_TC5182.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC5183.4dm} | 7 +- .../Sources/Methods/ut_2_R3487_TC5184.4dm} | 7 +- .../Sources/Methods/ut_2_R3487_TC5185.4dm} | 7 +- .../Sources/Methods/ut_2_R3487_TC5186.4dm} | 7 +- .../Sources/Methods/ut_2_R3487_TC5187.4dm} | 0 .../Sources/Methods/ut_2_R3487_TC6295.4dm} | 2 +- .../Sources/Methods/ut_2_R3487_TC6296.4dm} | 2 +- .../Sources/Methods/ut_2_R3488_TC5311.4dm} | 2 +- .../Sources/Methods/ut_2_R3488_TC5313.4dm} | 2 +- .../Sources/Methods/ut_2_R3488_TC5314.4dm} | 3 +- .../Sources/Methods/ut_2_R3488_TC5315.4dm} | 3 +- .../Sources/Methods/ut_3_R11077_TC11162.4dm} | 1 - .../Project/Sources/catalog.4DCatalog | 0 .../Project/Sources/folders.json | 92 +++++++++++++++++++ .../Project/Sources/menus.json | 0 .../Project/Sources/settings.4DSettings | 0 .../{Build4D_UnitTests => }/README.md | 0 .../Resources/UnitTests.txt | 0 .../Resources/compilationError.4dm | 0 65 files changed, 306 insertions(+), 220 deletions(-) delete mode 100644 Build4D_UnitTests/Build4D_UnitTests/Project/Sources/folders.json rename Build4D_UnitTests/{Build4D_UnitTests => }/Documentation/Methods/onStartup.md (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Build4D_UnitTests.4DProject (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/DatabaseMethods/onStartup.4dm (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/compilationError.4dm (100%) create mode 100644 Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/compilerMethods.4dm (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/logGitHubActions.4dm (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4743.4dm => Project/Sources/Methods/mut_2_R3486_TC4743.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4749.4dm => Project/Sources/Methods/mut_2_R3486_TC4749.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/onError.4dm (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/onStartup.4dm (78%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/runAutomaticUnitTests.4dm (65%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/Methods/runManualUnitTests.4dm (100%) create mode 100644 Build4D_UnitTests/Project/Sources/Methods/runUnitTests1.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/runUnitTests2.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/runUnitTests3.4dm rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4734.4dm => Project/Sources/Methods/ut_1_R3485_TC4734.4dm} (88%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4736.4dm => Project/Sources/Methods/ut_1_R3485_TC4736.4dm} (92%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6022.4dm => Project/Sources/Methods/ut_1_R3485_TC6022.4dm} (89%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6023.4dm => Project/Sources/Methods/ut_1_R3485_TC6023.4dm} (89%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5319.4dm => Project/Sources/Methods/ut_1_R3489_TC5319.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5321.4dm => Project/Sources/Methods/ut_1_R3489_TC5321.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5322.4dm => Project/Sources/Methods/ut_1_R3489_TC5322.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm => Project/Sources/Methods/ut_1_R3490_TC5331.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm => Project/Sources/Methods/ut_1_R3490_TC5333.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5334.4dm => Project/Sources/Methods/ut_1_R3491_TC5334.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5336.4dm => Project/Sources/Methods/ut_1_R3491_TC5336.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5337.4dm => Project/Sources/Methods/ut_1_R3491_TC5337.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4725.4dm => Project/Sources/Methods/ut_2_R3484_TC4725.4dm} (90%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4732.4dm => Project/Sources/Methods/ut_2_R3484_TC4732.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4733.4dm => Project/Sources/Methods/ut_2_R3484_TC4733.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4737.4dm => Project/Sources/Methods/ut_2_R3486_TC4737.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4739.4dm => Project/Sources/Methods/ut_2_R3486_TC4739.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4741.4dm => Project/Sources/Methods/ut_2_R3486_TC4741.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4745.4dm => Project/Sources/Methods/ut_2_R3486_TC4745.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4746.4dm => Project/Sources/Methods/ut_2_R3486_TC4746.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4747.4dm => Project/Sources/Methods/ut_2_R3486_TC4747.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4750.4dm => Project/Sources/Methods/ut_2_R3486_TC4750.4dm} (97%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5165.4dm => Project/Sources/Methods/ut_2_R3487_TC5165.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5167.4dm => Project/Sources/Methods/ut_2_R3487_TC5167.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5169.4dm => Project/Sources/Methods/ut_2_R3487_TC5169.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5170.4dm => Project/Sources/Methods/ut_2_R3487_TC5170.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5182.4dm => Project/Sources/Methods/ut_2_R3487_TC5182.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5183.4dm => Project/Sources/Methods/ut_2_R3487_TC5183.4dm} (82%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5184.4dm => Project/Sources/Methods/ut_2_R3487_TC5184.4dm} (83%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5185.4dm => Project/Sources/Methods/ut_2_R3487_TC5185.4dm} (81%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5186.4dm => Project/Sources/Methods/ut_2_R3487_TC5186.4dm} (81%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5187.4dm => Project/Sources/Methods/ut_2_R3487_TC5187.4dm} (100%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6295.4dm => Project/Sources/Methods/ut_2_R3487_TC6295.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6296.4dm => Project/Sources/Methods/ut_2_R3487_TC6296.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5311.4dm => Project/Sources/Methods/ut_2_R3488_TC5311.4dm} (95%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5313.4dm => Project/Sources/Methods/ut_2_R3488_TC5313.4dm} (94%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5314.4dm => Project/Sources/Methods/ut_2_R3488_TC5314.4dm} (87%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5315.4dm => Project/Sources/Methods/ut_2_R3488_TC5315.4dm} (87%) rename Build4D_UnitTests/{Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm => Project/Sources/Methods/ut_3_R11077_TC11162.4dm} (54%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/catalog.4DCatalog (100%) create mode 100644 Build4D_UnitTests/Project/Sources/folders.json rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/menus.json (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Project/Sources/settings.4DSettings (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/README.md (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Resources/UnitTests.txt (100%) rename Build4D_UnitTests/{Build4D_UnitTests => }/Resources/compilationError.4dm (100%) diff --git a/.gitignore b/.gitignore index f3f8c6e..901d2e7 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,5 @@ zzz*.4dm # Build *Test/ -*buildApp.4DSettings *Build/ +Build4D/Settings/buildApp.4DSettings diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 3de7fed..2149a6e 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -24,12 +24,12 @@ Class constructor($target : Text; $customSettings : Object) This._validInstance:=True This._isCurrentProject:=True This._projectFile:=File(Structure file(*); fk platform path) - This._currentProjectPackage:=This._projectFile.parent.parent + This._currentProjectPackage:=Folder(Folder("/PACKAGE/"; *).platformPath; fk platform path) If (($settings#Null) && ($settings.projectFile#Null) && \ ((Value type($settings.projectFile)=Is object) && OB Instance of($settings.projectFile; 4D.File)) || \ ((Value type($settings.projectFile)=Is text) && ($settings.projectFile#""))) This._isCurrentProject:=False - This._projectFile:=This._resolvePath($settings.projectFile; Folder(Folder("/PACKAGE/"; *).platformPath; fk platform path)) + This._projectFile:=This._resolvePath($settings.projectFile; This._currentProjectPackage) If (Not(This._projectFile.exists)) This._validInstance:=False This._log(New object(\ @@ -74,7 +74,7 @@ Function _overrideSettings($settings : Object) For each ($entry; $entries) Case of : ($entry.key="destinationFolder") - This.settings.destinationFolder:=This._resolvePath($settings.destinationFolder; This._projectPackage) + This.settings.destinationFolder:=This._resolvePath($settings.destinationFolder; This._currentProjectPackage) If (Not(OB Instance of(This.settings.destinationFolder; 4D.Folder))) This._validInstance:=False Else @@ -94,7 +94,7 @@ Function _overrideSettings($settings : Object) If (Value type($settings.sourceAppFolder)=Is text) $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" End if - This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; Null) + This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; This._currentProjectPackage) If ((This.settings.sourceAppFolder=Null) || (Not(OB Instance of(This.settings.sourceAppFolder; 4D.Folder)) || (Not(This.settings.sourceAppFolder.exists)))) This._validInstance:=False This._log(New object(\ @@ -533,61 +533,28 @@ Function _setAppOptions() : Boolean End for each End if //If (This.settings.versioning.creator#Null) - //$appInfo._unknown:=This.settings.versioning.creator - //End if - //If (This.settings.versioning.comment#Null) - //$appInfo.Comment:=This.settings.versioning.comment - //End if - //If (This.settings.versioning.companyName#Null) - //$appInfo.CompanyName:=This.settings.versioning.companyName - //End if - //If (This.settings.versioning.fileDescription#Null) - //$appInfo.FileDescription:=This.settings.versioning.fileDescription - //End if - //If (This.settings.versioning.internalName#Null) - //$appInfo.InternalName:=This.settings.versioning.internalName - //End if - //If (This.settings.versioning.legalTrademark#Null) - //$appInfo.LegalTrademarks:=This.settings.versioning.legalTrademark - //End if - //If (This.settings.versioning.privateBuild#Null) - //$appInfo.PrivateBuild:=This.settings.versioning.privateBuild - //End if - //If (This.settings.versioning.specialBuild#Null) - //$appInfo.SpecialBuild:=This.settings.versioning.specialBuild + //$appInfo._unknown:=Substring(This.settings.versioning.creator; 1; 4) //End if Else // Windows If (This.settings.versioning.version#Null) - $exeInfo.ProductVersion:=This.settings.versioning.version // + $exeInfo.ProductVersion:=This.settings.versioning.version End if If (This.settings.versioning.copyright#Null) - $exeInfo.LegalCopyright:=This.settings.versioning.copyright // + $exeInfo.LegalCopyright:=This.settings.versioning.copyright End if - //If (This.settings.versioning.creator#Null) - //$exeInfo.Creator:=This.settings.versioning.creator - //End if - //If (This.settings.versioning.comment#Null) - //$exeInfo.Comment:=This.settings.versioning.comment - //End if If (This.settings.versioning.companyName#Null) $exeInfo.CompanyName:=This.settings.versioning.companyName End if If (This.settings.versioning.fileDescription#Null) - $exeInfo.FileDescription:=This.settings.versioning.fileDescription // + $exeInfo.FileDescription:=This.settings.versioning.fileDescription End if If (This.settings.versioning.internalName#Null) $exeInfo.InternalName:=This.settings.versioning.internalName End if If (This.settings.versioning.legalTrademark#Null) - $exeInfo.LegalTrademarks:=This.settings.versioning.legalTrademark // No defined in setAppInfo + $exeInfo.LegalTrademarks:=This.settings.versioning.legalTrademark End if - //If (This.settings.versioning.privateBuild#Null) - //$exeInfo.PrivateBuild:=This.settings.versioning.privateBuild - //End if - //If (This.settings.versioning.specialBuild#Null) - //$exeInfo.SpecialBuild:=This.settings.versioning.specialBuild - //End if End if End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/folders.json b/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/folders.json deleted file mode 100644 index 995cc8d..0000000 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/folders.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "Default Classes": {}, - "Default Folder": { - "groups": [ - "Default Classes", - "Default Forms", - "Default Project Methods", - "Default Tables" - ] - }, - "Default Forms": {}, - "Default Project Methods": {}, - "Default Tables": {}, - "R3484": { - "methods": [ - "ut_R3484_TC4725", - "ut_R3484_TC4732", - "ut_R3484_TC4733" - ] - }, - "R3485": { - "methods": [ - "ut_R3485_TC4734", - "ut_R3485_TC4736", - "ut_R3485_TC6022", - "ut_R3485_TC6023" - ] - }, - "R3486": { - "methods": [ - "mut_R3486_TC4743", - "mut_R3486_TC4749", - "ut_R3486_TC4737", - "ut_R3486_TC4739", - "ut_R3486_TC4741", - "ut_R3486_TC4745", - "ut_R3486_TC4746", - "ut_R3486_TC4747", - "ut_R3486_TC4750" - ] - }, - "R3487": { - "methods": [ - "ut_R3487_TC5165", - "ut_R3487_TC5167", - "ut_R3487_TC5169", - "ut_R3487_TC5170", - "ut_R3487_TC5182", - "ut_R3487_TC5183", - "ut_R3487_TC5184", - "ut_R3487_TC5185", - "ut_R3487_TC5186", - "ut_R3487_TC5187", - "ut_R3487_TC6295", - "ut_R3487_TC6296" - ] - }, - "R3488": { - "methods": [ - "ut_R3488_TC5311", - "ut_R3488_TC5313", - "ut_R3488_TC5314", - "ut_R3488_TC5315" - ] - }, - "R3489": { - "methods": [ - "ut_R3489_TC5319", - "ut_R3489_TC5321", - "ut_R3489_TC5322" - ] - }, - "R3490": { - "methods": [ - "ut_R3490_TC5331", - "ut_R3490_TC5333" - ] - }, - "R3491": { - "methods": [ - "ut_R3491_TC5334", - "ut_R3491_TC5336", - "ut_R3491_TC5337" - ] - }, - "trash": {} -} \ No newline at end of file diff --git a/Build4D_UnitTests/Build4D_UnitTests/Documentation/Methods/onStartup.md b/Build4D_UnitTests/Documentation/Methods/onStartup.md similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Documentation/Methods/onStartup.md rename to Build4D_UnitTests/Documentation/Methods/onStartup.md diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Build4D_UnitTests.4DProject b/Build4D_UnitTests/Project/Build4D_UnitTests.4DProject similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Build4D_UnitTests.4DProject rename to Build4D_UnitTests/Project/Build4D_UnitTests.4DProject diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/DatabaseMethods/onStartup.4dm b/Build4D_UnitTests/Project/Sources/DatabaseMethods/onStartup.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/DatabaseMethods/onStartup.4dm rename to Build4D_UnitTests/Project/Sources/DatabaseMethods/onStartup.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilationError.4dm b/Build4D_UnitTests/Project/Sources/Methods/compilationError.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilationError.4dm rename to Build4D_UnitTests/Project/Sources/Methods/compilationError.4dm diff --git a/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm b/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm new file mode 100644 index 0000000..a76b29e --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm @@ -0,0 +1,2 @@ +//%attributes = {} +ut_1_R3490_TC5331 diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilerMethods.4dm b/Build4D_UnitTests/Project/Sources/Methods/compilerMethods.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilerMethods.4dm rename to Build4D_UnitTests/Project/Sources/Methods/compilerMethods.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/logGitHubActions.4dm b/Build4D_UnitTests/Project/Sources/Methods/logGitHubActions.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/logGitHubActions.4dm rename to Build4D_UnitTests/Project/Sources/Methods/logGitHubActions.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4743.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4743.4dm rename to Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4749.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/mut_R3486_TC4749.4dm rename to Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onError.4dm b/Build4D_UnitTests/Project/Sources/Methods/onError.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onError.4dm rename to Build4D_UnitTests/Project/Sources/Methods/onError.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm b/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm similarity index 78% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm rename to Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm index bb83217..a8567e8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm @@ -9,17 +9,17 @@ If (Count parameters=0) // Execute code in a new worker Use (Storage) Storage.settings:=New shared object("rootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path)) //"projectName"; File(Structure file(*); fk platform path).name; \ - "externalRootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path).parent.folder("Build4D_External"); \ - "externalProjectName"; ""; \ - "userInterface"; Not(Get application info.headless); \ - "logRunFile"; File($rootFolder+"UT_run.log").path; \ - "logErrorFile"; File($rootFolder+"UT_errors.log").path\ - ) + "externalRootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path).parent.folder("Build4D_External"); \ + "externalProjectName"; ""; \ + "userInterface"; Not(Get application info.headless); \ + "logRunFile"; File($rootFolder+"UT_run.log").path; \ + "logErrorFile"; File($rootFolder+"UT_errors.log").path\ + ) End use Use (Storage.settings) Storage.settings.projectName:=File(Structure file(*); fk platform path).name Storage.settings.userInterface:=Not(Get application info.headless) - Storage.settings.externalProjectRootFolder:=Storage.settings.rootFolder.parent.folder("Build4D_External") + Storage.settings.externalProjectRootFolder:=Storage.settings.rootFolder.folder("Build4D_External") Storage.settings.externalProjectName:="Build4D_External" Storage.settings.externalProjectFile:=Storage.settings.externalProjectRootFolder.file("Project/Build4D_External.4DProject") Storage.settings.logRunFile:=Storage.settings.rootFolder.file("UT_run.log") diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm b/Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm similarity index 65% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm rename to Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm index 1b0eb95..8760621 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/runAutomaticUnitTests.4dm @@ -2,12 +2,14 @@ //Performs all automatic unit tests var $artifactsFolder : 4D.Folder +var $errorsLogFile : 4D.File $artifactsFolder:=Storage.settings.rootFolder.parent.parent.folder("Artifacts") $artifactsFolder.folder("Build4D.4dbase").delete(Delete with contents) +$errorsLogFile:=Storage.settings.logErrorFile Storage.settings.logRunFile.delete() Storage.settings.logErrorFile.delete() -Storage.settings.rootFolder.file("UT_start.log").setText(Timestamp) // Write a starting file to check for writing permission +Storage.settings.rootFolder.file("UT_start.log").setText(Timestamp) Storage.settings.rootFolder.file("UT_end.log").delete() var $errorMethod : Text @@ -22,30 +24,27 @@ logGitHubActions("::group::Storage content") logGitHubActions(New object("Storage content"; Storage)) logGitHubActions("::endgroup::") -var $errorsLogFile : 4D.File -$errorsLogFile:=Storage.settings.logErrorFile -If (Not($errorsLogFile.exists)) // If project unit tests failed, no need to perform component unit tests... - // Check compilation first - logGitHubActions("::group::Compilation checking (compilationTest)") - compilationTest - logGitHubActions("::endgroup::") +// Check compilation first +logGitHubActions("::group::Compilation checking (compilationTest)") +compilationTest +logGitHubActions("::endgroup::") + +If (Not($errorsLogFile.exists)) // Compilation Ok -> execute all unit tests methods + + // Execute all automatic test methods + ARRAY TEXT($methods; 0) + var $m : Integer + METHOD GET NAMES($methods; "ut_@") + SORT ARRAY($methods) + For ($m; 1; Size of array($methods)) + logGitHubActions("::group::"+$methods{$m}) + EXECUTE METHOD($methods{$m}) + logGitHubActions("::endgroup::") + End for - If (Not($errorsLogFile.exists)) // Compilation Ok -> execute all unit tests methods - - // Execute all automatic test methods - ARRAY TEXT($methods; 0) - var $m : Integer - METHOD GET NAMES($methods; "ut_@") - SORT ARRAY($methods) - For ($m; 1; Size of array($methods)) - logGitHubActions("::group::"+$methods{$m}) - EXECUTE METHOD($methods{$m}) - logGitHubActions("::endgroup::") - End for - - End if End if + Storage.settings.rootFolder.file("UT_end.log").setText(Timestamp) logGitHubActions("Unit Tests end") diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/runManualUnitTests.4dm b/Build4D_UnitTests/Project/Sources/Methods/runManualUnitTests.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/runManualUnitTests.4dm rename to Build4D_UnitTests/Project/Sources/Methods/runManualUnitTests.4dm diff --git a/Build4D_UnitTests/Project/Sources/Methods/runUnitTests1.4dm b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests1.4dm new file mode 100644 index 0000000..5028544 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests1.4dm @@ -0,0 +1,47 @@ +//%attributes = {} +//Performs automatic unit tests on target 1: compiledProject + +var $target : Text +$target:=Substring(Current method name; Length(Current method name)) + +Storage.settings.logRunFile.delete() +Storage.settings.logErrorFile.delete() +Storage.settings.rootFolder.file("UT_start.log").setText(Timestamp) +Storage.settings.rootFolder.file("UT_end.log").delete() + +var $errorMethod : Text +$errorMethod:=Method called on error +ON ERR CALL("onError") + +METHOD SET CODE("compilationError"; ""; *) +SET ASSERT ENABLED(True) + +logGitHubActions("Unit Tests "+$target+" start") +logGitHubActions("::group::Storage content") +logGitHubActions(New object("Storage content"; Storage)) +logGitHubActions("::endgroup::") + +// Execute all automatic test methods +ARRAY TEXT($methods; 0) +var $m : Integer +METHOD GET NAMES($methods; "ut_"+$target+"_@") +SORT ARRAY($methods) +For ($m; 1; Size of array($methods)) + logGitHubActions("::group::"+$methods{$m}) + EXECUTE METHOD($methods{$m}) + logGitHubActions("::endgroup::") +End for + +Storage.settings.rootFolder.file("UT_end.log").setText(Timestamp) +logGitHubActions("Unit Tests "+$target+" end") + +If (Storage.settings.userInterface) + If (Storage.settings.logErrorFile.exists) + ALERT("Unit tests "+$target+" FAILED") + SHOW ON DISK(Storage.settings.logErrorFile.platformPath) + Else + ALERT("Unit tests "+$target+" passed") + End if +End if + +ON ERR CALL($errorMethod) diff --git a/Build4D_UnitTests/Project/Sources/Methods/runUnitTests2.4dm b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests2.4dm new file mode 100644 index 0000000..a19e54e --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests2.4dm @@ -0,0 +1,47 @@ +//%attributes = {} +//Performs automatic unit tests on target 1: component + +var $target : Text +$target:=Substring(Current method name; Length(Current method name)) + +Storage.settings.logRunFile.delete() +Storage.settings.logErrorFile.delete() +Storage.settings.rootFolder.file("UT_start.log").setText(Timestamp) +Storage.settings.rootFolder.file("UT_end.log").delete() + +var $errorMethod : Text +$errorMethod:=Method called on error +ON ERR CALL("onError") + +METHOD SET CODE("compilationError"; ""; *) +SET ASSERT ENABLED(True) + +logGitHubActions("Unit Tests "+$target+" start") +logGitHubActions("::group::Storage content") +logGitHubActions(New object("Storage content"; Storage)) +logGitHubActions("::endgroup::") + +// Execute all automatic test methods +ARRAY TEXT($methods; 0) +var $m : Integer +METHOD GET NAMES($methods; "ut_"+$target+"_@") +SORT ARRAY($methods) +For ($m; 1; Size of array($methods)) + logGitHubActions("::group::"+$methods{$m}) + EXECUTE METHOD($methods{$m}) + logGitHubActions("::endgroup::") +End for + +Storage.settings.rootFolder.file("UT_end.log").setText(Timestamp) +logGitHubActions("Unit Tests "+$target+" end") + +If (Storage.settings.userInterface) + If (Storage.settings.logErrorFile.exists) + ALERT("Unit tests "+$target+" FAILED") + SHOW ON DISK(Storage.settings.logErrorFile.platformPath) + Else + ALERT("Unit tests "+$target+" passed") + End if +End if + +ON ERR CALL($errorMethod) diff --git a/Build4D_UnitTests/Project/Sources/Methods/runUnitTests3.4dm b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests3.4dm new file mode 100644 index 0000000..578451f --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/runUnitTests3.4dm @@ -0,0 +1,47 @@ +//%attributes = {} +//Performs automatic unit tests on target 1: standalone + +var $target : Text +$target:=Substring(Current method name; Length(Current method name)) + +Storage.settings.logRunFile.delete() +Storage.settings.logErrorFile.delete() +Storage.settings.rootFolder.file("UT_start.log").setText(Timestamp) +Storage.settings.rootFolder.file("UT_end.log").delete() + +var $errorMethod : Text +$errorMethod:=Method called on error +ON ERR CALL("onError") + +METHOD SET CODE("compilationError"; ""; *) +SET ASSERT ENABLED(True) + +logGitHubActions("Unit Tests "+$target+" start") +logGitHubActions("::group::Storage content") +logGitHubActions(New object("Storage content"; Storage)) +logGitHubActions("::endgroup::") + +// Execute all automatic test methods +ARRAY TEXT($methods; 0) +var $m : Integer +METHOD GET NAMES($methods; "ut_"+$target+"_@") +SORT ARRAY($methods) +For ($m; 1; Size of array($methods)) + logGitHubActions("::group::"+$methods{$m}) + EXECUTE METHOD($methods{$m}) + logGitHubActions("::endgroup::") +End for + +Storage.settings.rootFolder.file("UT_end.log").setText(Timestamp) +logGitHubActions("Unit Tests "+$target+" end") + +If (Storage.settings.userInterface) + If (Storage.settings.logErrorFile.exists) + ALERT("Unit tests "+$target+" FAILED") + SHOW ON DISK(Storage.settings.logErrorFile.platformPath) + Else + ALERT("Unit tests "+$target+" passed") + End if +End if + +ON ERR CALL($errorMethod) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4734.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm similarity index 88% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4734.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm index a48a066..0f64abb 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4734.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm @@ -37,7 +37,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -$destinationFolder:=Storage.settings.externalProjectRootFolder.parent.folder($build._projectFile.name+"_Build/CompiledProject/"+$build.settings.buildName) +$destinationFolder:=$build._projectPackage.parent.folder($build._projectFile.name+"_Build/CompiledProject/"+$build.settings.buildName) ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong default destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4734)") $success:=$build.build() @@ -48,5 +48,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.parent.folder($build._projectFile.name+"_Build").delete(fk recursive) - +$build._projectPackage.parent.folder($build._projectFile.name+"_Build").delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4736.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm similarity index 92% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4736.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm index 89d25b5..ebf12ad 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC4736.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm @@ -38,7 +38,6 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -$destinationFolder:=Storage.settings.externalProjectRootFolder.folder("Test") ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong specified destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") $success:=$build.build() @@ -49,5 +48,5 @@ $compiledProject:=$destinationFolder.file($build.settings.buildName+".4DZ") ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6022.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm similarity index 89% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6022.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm index b544434..3de98e7 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6022.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm @@ -41,9 +41,9 @@ $success:=$build.build() ASSERT($success; "(External project) Compiled project build should success"+$link) -$compiledProject:=Storage.settings.externalProjectRootFolder.folder("Test").file(Storage.settings.externalProjectName+".4DZ") +$compiledProject:=Folder("/PACKAGE/Test"; *).file(Storage.settings.externalProjectName+".4DZ") ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6023.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm similarity index 89% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6023.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm index 6782059..799c43f 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3485_TC6023.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm @@ -38,15 +38,13 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -$destinationFolder:=Storage.settings.externalProjectRootFolder.folder("Test") ASSERT($build.settings.buildName="TEST"; "(External project) Wrong specified build name: "+$build.settings.buildName+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") $success:=$build.build() ASSERT($success; "(External project) Compiled project build should success"+$link) -$compiledProject:=$destinationFolder.file("TEST.4DZ") ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5319.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5319.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm index 40147e6..a407b9f 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5319.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm @@ -47,4 +47,4 @@ $zip:=ZIP Read archive($compiledProject) ASSERT($zip=Null; "(External project) Compiled project 4DZ file shouldn't be unzippable"+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5321.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5321.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm index 3fdd9cd..92a53d6 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5321.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm @@ -49,4 +49,4 @@ ASSERT($zip#Null; "Compiled project 4DZ file should be unzippable"+$link) $zip:=Null // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5322.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5322.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm index 82f985b..179b1a8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3489_TC5322.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm @@ -47,4 +47,4 @@ ASSERT($zip#Null; "(External project) Compiled project 4DZ file should be unzipp $zip:=Null // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5331.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3490_TC5333.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5334.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5334.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm index cc8e0a8..dc3253e 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5334.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm @@ -43,4 +43,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(External project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5336.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5336.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm index da55787..75ee083 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5336.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm @@ -43,4 +43,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists=False; "(External project) Compiled project 4DZ file should not exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5337.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5337.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm index a99f9d1..3cfad7a 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3491_TC5337.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm @@ -42,4 +42,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(External project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4725.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm similarity index 90% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4725.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm index b3edb36..d2f20a8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4725.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm @@ -36,7 +36,6 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.Component.new($settings) -$destinationFolder:=Storage.settings.externalProjectRootFolder.folder("Test/"+$build.settings.buildName+".4dbase/") ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong custom destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() @@ -46,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($build.settings.destinationFolder.exists; "(External project) Component should be placed in the custom destination folder: "+$build.settings.destinationFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4732.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4732.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4732.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4732.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4733.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4733.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3484_TC4733.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4733.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4737.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4737.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4739.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4739.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm index 18c8513..d07518d 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4739.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm @@ -70,6 +70,6 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4741.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4741.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm index 8a04ade..b0313ec 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4741.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm @@ -71,5 +71,5 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4745.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4745.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm index 957df1e..1c53dd0 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4745.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4746.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4746.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm index 003d1d9..513fb26 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4746.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4747.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4747.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm index a1868f9..ddece27 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4747.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4750.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm similarity index 97% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4750.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm index 54b0281..55c6aaf 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3486_TC4750.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test"; *).delete(fk recursive) End if diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5165.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5165.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm index 63b8fd5..f30a7ba 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5165.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm @@ -46,5 +46,5 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation/") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5167.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5167.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm index e035f9f..2ee944f 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5167.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm @@ -46,5 +46,5 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5169.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5169.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm index aec16f4..c732e80 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5169.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm @@ -50,4 +50,4 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5170.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5170.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5182.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5182.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm index 74f96ba..5524a88 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5182.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm @@ -50,4 +50,4 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5183.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm similarity index 82% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5183.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm index 59f4d1c..fb180b9 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5183.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm @@ -35,10 +35,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.includePaths:=New collection(New object(\ -"source"; "./Documentation/"; \ -"destination"; Storage.settings.externalProjectRootFolder.folder("Test").path)\ -) $build:=cs.Build4D.Component.new($settings) @@ -46,8 +42,7 @@ $success:=$build.build() ASSERT($success; "(External project) Component build should success"+$link) -$includedFolder:=Storage.settings.externalProjectRootFolder.folder("Test/Documentation") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5184.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm similarity index 83% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5184.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm index 3a2547a..7895c82 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5184.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm @@ -35,10 +35,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.includePaths:=New collection(New object(\ -"source"; "./README.md"; \ -"destination"; Storage.settings.externalProjectRootFolder.folder("Test").path)\ -) $build:=cs.Build4D.Component.new($settings) @@ -46,8 +42,7 @@ $success:=$build.build() ASSERT($success; "(External project) Component build should success"+$link) -$includedFile:=Storage.settings.externalProjectRootFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5185.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm similarity index 81% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5185.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm index cc25a3d..3bffddc 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5185.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm @@ -35,10 +35,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.includePaths:=New collection(New object(\ -"source"; Storage.settings.externalProjectRootFolder.folder("Documentation").path; \ -"destination"; Storage.settings.externalProjectRootFolder.folder("Test").path)\ -) $build:=cs.Build4D.Component.new($settings) @@ -46,8 +42,7 @@ $success:=$build.build() ASSERT($success; "(External project) Component build should success"+$link) -$includedFolder:=Storage.settings.externalProjectRootFolder.folder("Test/Documentation") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5186.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm similarity index 81% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5186.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm index 4987522..5a97f38 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5186.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm @@ -35,10 +35,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.includePaths:=New collection(New object(\ -"source"; Storage.settings.externalProjectRootFolder.file("README.md").path; \ -"destination"; Storage.settings.externalProjectRootFolder.folder("Test").path)\ -) $build:=cs.Build4D.Component.new($settings) @@ -46,8 +42,7 @@ $success:=$build.build() ASSERT($success; "(External project) Component build should success"+$link) -$includedFile:=Storage.settings.externalProjectRootFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5187.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC5187.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6295.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6295.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm index 70b90dd..7f8c0f8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6295.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm @@ -45,4 +45,4 @@ $includedFolder:=$build.settings.destinationFolder.folder("Documentation/") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6296.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6296.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm index 6bd70da..5659dec 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3487_TC6296.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm @@ -45,4 +45,4 @@ $includedFile:=$build.settings.destinationFolder.file("README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5311.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm similarity index 95% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5311.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm index 5cc07ba..0255eed 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5311.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm @@ -43,4 +43,4 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") ASSERT($deletedFile.exists=False; "(External project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5313.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm similarity index 94% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5313.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm index e985ec8..2d612b8 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5313.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm @@ -43,4 +43,4 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(External project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5314.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm similarity index 87% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5314.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm index 5a0752d..b42aef4 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5314.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm @@ -32,7 +32,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.deletePaths:=New collection(File(Storage.settings.externalProjectRootFolder.path+"Test/"+$settings.buildName+".4dbase/Resources/UnitTests.txt")) $build:=cs.Build4D.Component.new($settings) @@ -44,4 +43,4 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") ASSERT($deletedFile.exists=False; "(External project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5315.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm similarity index 87% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5315.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm index 2c2370b..e410f5b 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/ut_R3488_TC5315.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm @@ -32,7 +32,6 @@ Folder("/PACKAGE/Test"; *).delete(fk recursive) // MARK:- External project $settings.projectFile:=Storage.settings.externalProjectFile -$settings.deletePaths:=New collection(Folder(Storage.settings.externalProjectRootFolder.path+"Test/"+$settings.buildName+".4dbase/Resources/")) $build:=cs.Build4D.Component.new($settings) @@ -44,4 +43,4 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(External project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) +Folder("/PACKAGE/Test"; *).delete(fk recursive) diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm similarity index 54% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm index 3e8d5fe..64fe454 100644 --- a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/Methods/compilationTest.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm @@ -1,2 +1 @@ //%attributes = {} -ut_R3490_TC5331 diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog b/Build4D_UnitTests/Project/Sources/catalog.4DCatalog similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/catalog.4DCatalog rename to Build4D_UnitTests/Project/Sources/catalog.4DCatalog diff --git a/Build4D_UnitTests/Project/Sources/folders.json b/Build4D_UnitTests/Project/Sources/folders.json new file mode 100644 index 0000000..697d0e6 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/folders.json @@ -0,0 +1,92 @@ +{ + "1_R3485": { + "methods": [ + "ut_1_R3485_TC4734", + "ut_1_R3485_TC4736", + "ut_1_R3485_TC6022", + "ut_1_R3485_TC6023" + ] + }, + "1_R3489": { + "methods": [ + "ut_1_R3489_TC5319", + "ut_1_R3489_TC5321", + "ut_1_R3489_TC5322" + ] + }, + "1_R3490": { + "methods": [ + "ut_1_R3490_TC5331", + "ut_1_R3490_TC5333" + ] + }, + "1_R3491": { + "methods": [ + "ut_1_R3491_TC5334", + "ut_1_R3491_TC5336", + "ut_1_R3491_TC5337" + ] + }, + "2_R3484": { + "methods": [ + "ut_2_R3484_TC4725", + "ut_2_R3484_TC4732", + "ut_2_R3484_TC4733" + ] + }, + "2_R3486": { + "methods": [ + "mut_2_R3486_TC4743", + "mut_2_R3486_TC4749", + "ut_2_R3486_TC4737", + "ut_2_R3486_TC4739", + "ut_2_R3486_TC4741", + "ut_2_R3486_TC4745", + "ut_2_R3486_TC4746", + "ut_2_R3486_TC4747", + "ut_2_R3486_TC4750" + ] + }, + "2_R3487": { + "methods": [ + "ut_2_R3487_TC5165", + "ut_2_R3487_TC5167", + "ut_2_R3487_TC5169", + "ut_2_R3487_TC5170", + "ut_2_R3487_TC5182", + "ut_2_R3487_TC5183", + "ut_2_R3487_TC5184", + "ut_2_R3487_TC5185", + "ut_2_R3487_TC5186", + "ut_2_R3487_TC5187", + "ut_2_R3487_TC6295", + "ut_2_R3487_TC6296" + ] + }, + "2_R3488": { + "methods": [ + "ut_2_R3488_TC5311", + "ut_2_R3488_TC5313", + "ut_2_R3488_TC5314", + "ut_2_R3488_TC5315" + ] + }, + "3_R11077": { + "methods": [ + "ut_3_R11077_TC11162" + ] + }, + "Default Classes": {}, + "Default Folder": { + "groups": [ + "Default Classes", + "Default Forms", + "Default Project Methods", + "Default Tables" + ] + }, + "Default Forms": {}, + "Default Project Methods": {}, + "Default Tables": {}, + "trash": {} +} \ No newline at end of file diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/menus.json b/Build4D_UnitTests/Project/Sources/menus.json similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/menus.json rename to Build4D_UnitTests/Project/Sources/menus.json diff --git a/Build4D_UnitTests/Build4D_UnitTests/Project/Sources/settings.4DSettings b/Build4D_UnitTests/Project/Sources/settings.4DSettings similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Project/Sources/settings.4DSettings rename to Build4D_UnitTests/Project/Sources/settings.4DSettings diff --git a/Build4D_UnitTests/Build4D_UnitTests/README.md b/Build4D_UnitTests/README.md similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/README.md rename to Build4D_UnitTests/README.md diff --git a/Build4D_UnitTests/Build4D_UnitTests/Resources/UnitTests.txt b/Build4D_UnitTests/Resources/UnitTests.txt similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Resources/UnitTests.txt rename to Build4D_UnitTests/Resources/UnitTests.txt diff --git a/Build4D_UnitTests/Build4D_UnitTests/Resources/compilationError.4dm b/Build4D_UnitTests/Resources/compilationError.4dm similarity index 100% rename from Build4D_UnitTests/Build4D_UnitTests/Resources/compilationError.4dm rename to Build4D_UnitTests/Resources/compilationError.4dm From 69fd1ae66a7ccd073c47a56594f53950440af24f Mon Sep 17 00:00:00 2001 From: Dev14D Date: Mon, 12 Jun 2023 16:18:07 +0200 Subject: [PATCH 17/29] Update Doc --- .../Documentation/Classes/CompiledProject.md | 12 +++++------ Build4D/Documentation/Classes/Component.md | 12 +++++------ Build4D/Documentation/Classes/Standalone.md | 20 +++++++++---------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Build4D/Documentation/Classes/CompiledProject.md b/Build4D/Documentation/Classes/CompiledProject.md index 6d9dd7e..fc7dcd7 100644 --- a/Build4D/Documentation/Classes/CompiledProject.md +++ b/Build4D/Documentation/Classes/CompiledProject.md @@ -20,15 +20,15 @@ $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| |buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file. Pass the project file path if you want to build an external project. Not necessary if it is a current project.| -|destinationFolder | Folder or String | Folder where the build will be generated. Defined by the component if missing in the custom settings.| -|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| |obfuscated | Boolean | True if the 4DZ shall not be dezippable.| |includePaths[] | Collection of Objects | Collection of folders and files to include.| -|includePaths[].source | String | Source folder or file path (relative to the built project/absolute/filesystem strings).| -|includePaths[].destination | String | Destination folder path (relative to the built project/absolute/filesystem strings).| -|deletePaths[] | Collection of Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| +|includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem strings).| +|includePaths[].destination | Folder, File, or String | Destination folder path (relative to the built project/absolute/filesystem).| +|deletePaths[] | Collection of Folders, Files, or Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem).| |logger | Formula | Formula called when a log is written.| ### build() diff --git a/Build4D/Documentation/Classes/Component.md b/Build4D/Documentation/Classes/Component.md index 744568c..07612c1 100644 --- a/Build4D/Documentation/Classes/Component.md +++ b/Build4D/Documentation/Classes/Component.md @@ -20,15 +20,15 @@ $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| |buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file. Pass the project file path if you want to build an external project. Not necessary if it is a current project.| -|destinationFolder | Folder or String | Folder where the build will be generated. Defined by the component if missing in the custom settings.| -|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| |obfuscated | Boolean | True if the 4DZ shall not be dezippable.| |includePaths[] | Collection of Objects | Collection of folders and files to include.| -|includePaths[].source | String | Source folder or file path (relative to the built project/absolute/filesystem strings).| -|includePaths[].destination | String | Destination folder path (relative to the built project/absolute/filesystem strings).| -|deletePaths[] | Collection of Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| +|includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem).| +|includePaths[].destination | Folder, File, or String | Destination folder or file path (relative to the built project/absolute/filesystem).| +|deletePaths[] | Collection of Folders, Files, or Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| |signApplication.macSignature | Boolean | Signs the built applications.| |signApplication.macCertificate | String | Certificate name used for signature.| |signApplication.adHocSignature | Boolean | Signs the built applications with AdHoc signature if macSignature not performed.| diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index f8c03df..77fbb22 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -21,30 +21,28 @@ $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| |buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file. Pass the project file path if you want to build an external project. Not necessary if it is a current project.| -|destinationFolder | Folder or String | Folder where the build will be generated. Defined by the component if missing in the custom settings.| -|sourceAppFolder| Folder or String | Folder of the 4D Volume Desktop.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| +|sourceAppFolder| Folder or String | Folder of the 4D Volume Desktop (relative to the open project/absolute/filesystem).| |compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| |obfuscated | Boolean | True if the 4DZ shall not be dezippable.| -|lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName", "ByAppPath"| +|lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName" (Default value), "ByAppPath"| |useSDI| Boolean | On Windows, use the SDI interface mode instead of the MDI.| |startElevated| Boolean | On Windows, allow to start the Updater with elevated privileges.| |iconPath| File or String | File path of the icon to be used instead of the 4D Volume Desktop icon.| |versioning| Object | Object contains the contents of the application information.| |versioning.version| String | Version number | |versioning.copyright| String | Copyright text | -|versioning.creator| String | Creator code (4 characters maximum) (macOS only)| -|versioning.comment| String | Comment (Windows only) | -|versioning.companyName| String | Company name (Windows only)| +|versioning.companyName| String | Company name| |versioning.fileDescription| String | Description (Windows only)| |versioning.internalName| String | Internal name (Windows only)| |includePaths[] | Collection of Objects | Collection of folders and files to include.| -|includePaths[].source | String | Source folder or file path (relative to the built project/absolute/filesystem strings).| -|includePaths[].destination | String | Destination folder path (relative to the built project/absolute/filesystem strings).| -|deletePaths[] | Collection of Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| +|includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem).| +|includePaths[].destination | Folder, File, or String | Destination folder path (relative to the built project/absolute/filesystem).| +|deletePaths[] | Collection of Folder, File, or Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| |excludeModules| Collection of Strings | Collection of module names to exclude from final application. The module names can be found in the "BuildappOptionalModules.json" file in the resources of 4D application.| -|license| File or String | Unlimited desktop license file.| +|license| File or String | Unlimited desktop license file (relative to the built project/absolute/filesystem).| |signApplication.macSignature | Boolean | Signs the built applications.| |signApplication.macCertificate | String | Certificate name used for signature.| |signApplication.adHocSignature | Boolean | Signs the built applications with AdHoc signature if macSignature not performed.| From 5bb46f9aaee940dea8f1b1860e277779dbca9d78 Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Mon, 12 Jun 2023 20:27:36 +0200 Subject: [PATCH 18/29] Unit Tests part #1 Requirements <= 11084 --- .gitignore | 3 +- .../Sources/Classes/CompiledProject.4dm | 9 +++ Build4D/Project/Sources/Classes/Component.4dm | 9 +++ .../Project/Sources/Classes/Standalone.4dm | 74 ++++++++++++++++++ Build4D/Project/Sources/Classes/_core.4dm | 33 +------- .../Sources/Methods/buildComponent.4dm | 2 +- .../Sources/Methods/mut_2_R3486_TC4743.4dm | 6 +- .../Sources/Methods/mut_2_R3486_TC4749.4dm | 6 +- .../Sources/Methods/mut_3_R11079_TC11171.4dm | 75 +++++++++++++++++++ .../Project/Sources/Methods/onStartup.4dm | 14 +--- .../Sources/Methods/ut_1_R3485_TC4734.4dm | 4 +- .../Sources/Methods/ut_1_R3485_TC4736.4dm | 10 +-- .../Sources/Methods/ut_1_R3485_TC6022.4dm | 12 +-- .../Sources/Methods/ut_1_R3485_TC6023.4dm | 12 ++- .../Sources/Methods/ut_1_R3489_TC5319.4dm | 4 +- .../Sources/Methods/ut_1_R3489_TC5321.4dm | 4 +- .../Sources/Methods/ut_1_R3489_TC5322.4dm | 4 +- .../Sources/Methods/ut_1_R3490_TC5331.4dm | 2 +- .../Sources/Methods/ut_1_R3490_TC5333.4dm | 2 +- .../Sources/Methods/ut_1_R3491_TC5334.4dm | 4 +- .../Sources/Methods/ut_1_R3491_TC5336.4dm | 4 +- .../Sources/Methods/ut_1_R3491_TC5337.4dm | 4 +- .../Sources/Methods/ut_2_R3484_TC4725.4dm | 6 +- .../Sources/Methods/ut_2_R3486_TC4739.4dm | 4 +- .../Sources/Methods/ut_2_R3486_TC4741.4dm | 4 +- .../Sources/Methods/ut_2_R3486_TC4745.4dm | 4 +- .../Sources/Methods/ut_2_R3486_TC4746.4dm | 4 +- .../Sources/Methods/ut_2_R3486_TC4747.4dm | 4 +- .../Sources/Methods/ut_2_R3486_TC4750.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5165.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5167.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5169.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5170.4dm | 2 +- .../Sources/Methods/ut_2_R3487_TC5182.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5183.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5184.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5185.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5186.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC5187.4dm | 2 +- .../Sources/Methods/ut_2_R3487_TC6295.4dm | 4 +- .../Sources/Methods/ut_2_R3487_TC6296.4dm | 4 +- .../Sources/Methods/ut_2_R3488_TC5311.4dm | 4 +- .../Sources/Methods/ut_2_R3488_TC5313.4dm | 4 +- .../Sources/Methods/ut_2_R3488_TC5314.4dm | 4 +- .../Sources/Methods/ut_2_R3488_TC5315.4dm | 4 +- .../Sources/Methods/ut_3_R11077_TC11162.4dm | 49 ++++++++++++ .../Sources/Methods/ut_3_R11077_TC11164.4dm | 51 +++++++++++++ .../Sources/Methods/ut_3_R11078_TC11169.4dm | 69 +++++++++++++++++ .../Sources/Methods/ut_3_R11078_TC11170.4dm | 68 +++++++++++++++++ .../Sources/Methods/ut_3_R11081_TC.4dm | 65 ++++++++++++++++ .../Sources/Methods/ut_3_R11083_TC11190.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11083_TC11192.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11083_TC11958.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11084_TC11200.4dm | 44 +++++++++++ .../Project/Sources/folders.json | 75 ++++++++++++++++--- Build4D_UnitTests/Settings/UT_Settings.json | 5 ++ 56 files changed, 811 insertions(+), 137 deletions(-) create mode 100644 Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11164.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm create mode 100644 Build4D_UnitTests/Settings/UT_Settings.json diff --git a/.gitignore b/.gitignore index 901d2e7..5fa397c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,10 +22,11 @@ Thumbs.db *.4dbase/ UT_*.log Build_*.log +*.license4D Artifacts/ zzz*.4dm # Build *Test/ *Build/ -Build4D/Settings/buildApp.4DSettings +*buildApp.4DSettings diff --git a/Build4D/Project/Sources/Classes/CompiledProject.4dm b/Build4D/Project/Sources/Classes/CompiledProject.4dm index ea4d93f..5b2130b 100644 --- a/Build4D/Project/Sources/Classes/CompiledProject.4dm +++ b/Build4D/Project/Sources/Classes/CompiledProject.4dm @@ -10,6 +10,15 @@ Class constructor($customSettings : Object) This.settings.destinationFolder:=This.settings.destinationFolder.folder("CompiledProject/"+This.settings.buildName+"/") End if This._structureFolder:=This.settings.destinationFolder + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init successful."; \ + "severity"; Information message)) + Else + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init failed."; \ + "severity"; Error message)) End if //MARK:- diff --git a/Build4D/Project/Sources/Classes/Component.4dm b/Build4D/Project/Sources/Classes/Component.4dm index 7000a20..51c1ad2 100644 --- a/Build4D/Project/Sources/Classes/Component.4dm +++ b/Build4D/Project/Sources/Classes/Component.4dm @@ -11,6 +11,15 @@ Class constructor($customSettings : Object) End if This.settings.destinationFolder:=This.settings.destinationFolder.folder(This.settings.buildName+".4dbase/") This._structureFolder:=This.settings.destinationFolder + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init successful."; \ + "severity"; Information message)) + Else + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init failed."; \ + "severity"; Error message)) End if //MARK:- diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index 4172f35..73a6c77 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -2,6 +2,8 @@ Class extends _core //MARK:- Class constructor($customSettings : Object) + var $currentAppInfo; $sourceAppInfo : Object + var $fileCheck : Boolean Super("Standalone"; $customSettings) @@ -11,6 +13,78 @@ Class constructor($customSettings : Object) End if This.settings.destinationFolder:=This.settings.destinationFolder.folder(This.settings.buildName+Choose(Is macOS; ".app"; "")+"/") This._structureFolder:=This.settings.destinationFolder.folder(Choose(Is macOS; "Contents/"; "")+"Database/") + + //Checking license + If ((This.settings.license=Null) || (Not(OB Instance of(This.settings.license; 4D.File)))) + This._validInstance:=False + This._log(New object(\ + "function"; "License file checking"; \ + "message"; "License file is not defined"; \ + "severity"; Error message)) + Else + If (Not(This.settings.license.exists)) + This._validInstance:=False + This._log(New object(\ + "function"; "License file checking"; \ + "message"; "License file doesn't exist"; \ + "severity"; Error message; \ + "path"; This.settings.license.path)) + End if + End if + + //Checking source app + If ((This.settings.sourceAppFolder=Null) || (Not(OB Instance of(This.settings.sourceAppFolder; 4D.Folder)))) + This._validInstance:=False + This._log(New object(\ + "function"; "Source application folder checking"; \ + "message"; "Source application folder is not defined"; \ + "severity"; Error message)) + Else + If (Not(This.settings.sourceAppFolder.exists)) + This._log(New object(\ + "function"; "Source application folder checking"; \ + "message"; "Source application folder doesn't exist"; \ + "severity"; Error message; \ + "sourceAppFolder"; $settings.sourceAppFolder.path)) + Else + $fileCheck:=(Is macOS) ? This.settings.sourceAppFolder.file("Contents/MacOS/4D Volume Desktop").exists : This.settings.sourceAppFolder.file("4D Volume Desktop.4DE").exists + If (Not($fileCheck)) + This._log(New object(\ + "function"; "Source application folder checking"; \ + "message"; "Source application is not a 4D Volume Desktop"; \ + "severity"; Error message; \ + "sourceAppFolder"; $settings.sourceAppFolder.path)) + Else // Versions checking + $sourceAppInfo:=(Is macOS) ? This.settings.sourceAppFolder.file("Contents/Info.plist").getAppInfo() : This.settings.sourceAppFolder.file("Resources/Info.plist").getAppInfo() + $currentAppInfo:=(Is macOS) ? Folder(Application file; fk platform path).file("Contents/Info.plist").getAppInfo() : File(Application file; fk platform path).parent.file("Resources/Info.plist").getAppInfo() + If (($sourceAppInfo.CFBundleVersion=Null) || ($currentAppInfo.CFBundleVersion=Null) || ($sourceAppInfo.CFBundleVersion#$currentAppInfo.CFBundleVersion)) + This._validInstance:=False + This._log(New object(\ + "function"; "Source application version checking"; \ + "message"; "Source application version doesn't match to current application version"; \ + "severity"; Error message; \ + "sourceAppFolder"; $settings.sourceAppFolder.path)) + End if + End if + End if + End if + + If (This._validInstance) + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init successful."; \ + "severity"; Information message)) + Else + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init failed."; \ + "severity"; Error message)) + End if + Else + This._log(New object(\ + "function"; "Class constuctor"; \ + "message"; "Class init failed."; \ + "severity"; Error message)) End if //MARK:- diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 2149a6e..01ef858 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -58,17 +58,13 @@ Class constructor($target : Text; $customSettings : Object) "message"; "Destination folder automatically defined."; \ "severity"; Information message)) End if - This._log(New object(\ - "function"; "Class constuctor"; \ - "message"; "Class init successful."; \ - "severity"; Information message)) End if //MARK:- Function _overrideSettings($settings : Object) var $entries : Collection - var $entry; $currentAppInfo; $sourceAppInfo : Object + var $entry : Object $entries:=OB Entries($settings) For each ($entry; $entries) @@ -95,26 +91,6 @@ Function _overrideSettings($settings : Object) $settings.sourceAppFolder:=($settings.sourceAppFolder="@/") ? $settings.sourceAppFolder : $settings.sourceAppFolder+"/" End if This.settings.sourceAppFolder:=This._resolvePath($settings.sourceAppFolder; This._currentProjectPackage) - If ((This.settings.sourceAppFolder=Null) || (Not(OB Instance of(This.settings.sourceAppFolder; 4D.Folder)) || (Not(This.settings.sourceAppFolder.exists)))) - This._validInstance:=False - This._log(New object(\ - "function"; "Source application folder checking"; \ - "message"; "Source application folder doesn't exist"; \ - "severity"; Error message); \ - "sourceAppFolder"; $settings.sourceAppFolder) - - Else // Versions checking - $sourceAppInfo:=(Is macOS) ? This.settings.sourceAppFolder.file("Contents/Info.plist").getAppInfo() : This.settings.sourceAppFolder.file("Resources/Info.plist").getAppInfo() - $currentAppInfo:=(Is macOS) ? Folder(Application file; fk platform path).file("Contents/Info.plist").getAppInfo() : File(Application file; fk platform path).parent.file("Resources/Info.plist").getAppInfo() - If (($sourceAppInfo.CFBundleVersion=Null) || ($currentAppInfo.CFBundleVersion=Null) || ($sourceAppInfo.CFBundleVersion#$currentAppInfo.CFBundleVersion)) - This._validInstance:=False - This._log(New object(\ - "function"; "Source application version checking"; \ - "message"; "Source application version doesn't match to current application version"; \ - "severity"; Error message); \ - "sourceAppFolder"; $settings.sourceAppFolder) - End if - End if Else This.settings[$entry.key]:=$entry.value @@ -413,6 +389,7 @@ Function _create4DZ() : Boolean End if return True + //MARK:- Function _copySourceApp() : Boolean This._noError:=True This.settings.sourceAppFolder.copyTo(This.settings.destinationFolder.parent; This.settings.destinationFolder.fullName) @@ -532,9 +509,6 @@ Function _setAppOptions() : Boolean End if End for each End if - //If (This.settings.versioning.creator#Null) - //$appInfo._unknown:=Substring(This.settings.versioning.creator; 1; 4) - //End if Else // Windows If (This.settings.versioning.version#Null) @@ -552,9 +526,6 @@ Function _setAppOptions() : Boolean If (This.settings.versioning.internalName#Null) $exeInfo.InternalName:=This.settings.versioning.internalName End if - If (This.settings.versioning.legalTrademark#Null) - $exeInfo.LegalTrademarks:=This.settings.versioning.legalTrademark - End if End if End if diff --git a/Build4D/Project/Sources/Methods/buildComponent.4dm b/Build4D/Project/Sources/Methods/buildComponent.4dm index b2453b1..4c1b795 100644 --- a/Build4D/Project/Sources/Methods/buildComponent.4dm +++ b/Build4D/Project/Sources/Methods/buildComponent.4dm @@ -15,7 +15,7 @@ $targets:=(Is macOS) ? New collection("x86_64_generic"; "arm64_macOS_lib") : New $settings:=New object(\ "buildName"; "Build4D"; \ "compilerOptions"; New object("targets"; $targets); \ -"destinationFolder"; "../Build4D_UnitTests/Build4D_UnitTests/Components/"; \ +"destinationFolder"; "../Build4D_UnitTests/Components/"; \ "includePaths"; New collection(New object("source"; "Documentation/"))\ ) diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm index 1fe008c..5272669 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm @@ -48,7 +48,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -76,8 +76,10 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) SET ASSERT ENABLED($assertions) +Else + ALERT("macOS only!") End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm index 37d9344..080c6ec 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm @@ -49,7 +49,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -77,8 +77,10 @@ If (Is macOS) End if // Cleanup build folder - Storage.settings.externalProjectRootFolder.folder("Test").delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) SET ASSERT ENABLED($assertions) +Else + ALERT("macOS only!") End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm new file mode 100644 index 0000000..653921c --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm @@ -0,0 +1,75 @@ +//%attributes = {} +// Define a 4D Volume Desktop with the version number is not match the 4D Developer Edition version number +var $build : cs.Build4D.Standalone +var $settings : Object +var $success; $found : Boolean +var $link : Text +var $log : Object +var $assertions : Boolean + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +$assertions:=Get assert enabled +SET ASSERT ENABLED(True) + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application version checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(Current project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(Current project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application version checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(External project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(External project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +SET ASSERT ENABLED($assertions) diff --git a/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm b/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm index a8567e8..23a0284 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/onStartup.4dm @@ -3,20 +3,12 @@ If (Count parameters=0) // Execute code in a new worker - //var $rootFolder; $externalRootFolder : Text - //$rootFolder:=Folder(Folder(fk database folder; *).platformPath; fk platform path).path - //$externalRootFolder:=Folder($rootFolder).parent.folder("Build4D_External").path Use (Storage) - Storage.settings:=New shared object("rootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path)) - //"projectName"; File(Structure file(*); fk platform path).name; \ - "externalRootFolder"; Folder(Folder(fk database folder; *).platformPath; fk platform path).parent.folder("Build4D_External"); \ - "externalProjectName"; ""; \ - "userInterface"; Not(Get application info.headless); \ - "logRunFile"; File($rootFolder+"UT_run.log").path; \ - "logErrorFile"; File($rootFolder+"UT_errors.log").path\ - ) + Storage.settings:=New shared object() + Storage.settings:=OB Copy(JSON Parse(File("/PACKAGE/Settings/UT_Settings.json").getText()); ck shared) End use Use (Storage.settings) + Storage.settings.rootFolder:=Folder(Folder(fk database folder; *).platformPath; fk platform path) Storage.settings.projectName:=File(Structure file(*); fk platform path).name Storage.settings.userInterface:=Not(Get application info.headless) Storage.settings.externalProjectRootFolder:=Storage.settings.rootFolder.folder("Build4D_External") diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm index 0f64abb..6d9abff 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4734.4dm @@ -19,7 +19,7 @@ $settings.buildName:="Build4D" $build:=cs.Build4D.CompiledProject.new($settings) $destinationFolder:=$build._projectPackage.parent.folder($build._projectFile.name+"_Build/CompiledProject/"+$build.settings.buildName) -ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(Current project) Wrong default destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4734)") +ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(Current project) Wrong default destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() @@ -38,7 +38,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) $destinationFolder:=$build._projectPackage.parent.folder($build._projectFile.name+"_Build/CompiledProject/"+$build.settings.buildName) -ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong default destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4734)") +ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong default destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm index ebf12ad..0c7e8a1 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC4736.4dm @@ -19,8 +19,8 @@ $settings.destinationFolder:="./Test/" $build:=cs.Build4D.CompiledProject.new($settings) -$destinationFolder:=Folder("/PACKAGE/Test"; *) -ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(Current project) Wrong specified destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +$destinationFolder:=Folder("/PACKAGE/Test") +ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(Current project) Wrong specified destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() @@ -30,7 +30,7 @@ $compiledProject:=$destinationFolder.file($build.settings.buildName+".4DZ") ASSERT($compiledProject.exists; "(Current project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -38,7 +38,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong specified destination folder: "+$build.settings.destinationFolder.platformPath+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(External project) Wrong specified destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() @@ -48,5 +48,5 @@ $compiledProject:=$destinationFolder.file($build.settings.buildName+".4DZ") ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm index 3de98e7..f73e951 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6022.4dm @@ -17,17 +17,17 @@ $settings.destinationFolder:="./Test/" $build:=cs.Build4D.CompiledProject.new($settings) -ASSERT($build.settings.buildName=Storage.settings.projectName; "(Current project) Wrong default build name: "+$build.settings.buildName+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +ASSERT($build.settings.buildName=Storage.settings.projectName; "(Current project) Wrong default build name: "+$build.settings.buildName+$link) $success:=$build.build() ASSERT($success; "(Current project) Compiled project build should success"+$link) -$compiledProject:=Folder("/PACKAGE/Test"; *).file(Storage.settings.projectName+".4DZ") +$compiledProject:=Folder("/PACKAGE/Test").file(Storage.settings.projectName+".4DZ") ASSERT($compiledProject.exists; "(Current project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -35,15 +35,15 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -ASSERT($build.settings.buildName=Storage.settings.externalProjectName; "(External project) Wrong default build name: "+$build.settings.buildName+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +ASSERT($build.settings.buildName=Storage.settings.externalProjectName; "(External project) Wrong default build name: "+$build.settings.buildName+$link) $success:=$build.build() ASSERT($success; "(External project) Compiled project build should success"+$link) -$compiledProject:=Folder("/PACKAGE/Test"; *).file(Storage.settings.externalProjectName+".4DZ") +$compiledProject:=Folder("/PACKAGE/Test").file(Storage.settings.externalProjectName+".4DZ") ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm index 799c43f..eded00e 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3485_TC6023.4dm @@ -3,7 +3,6 @@ var $build : cs.Build4D.CompiledProject var $settings : Object var $success : Boolean -var $destinationFolder : 4D.Folder var $compiledProject : 4D.File var $link : Text $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" @@ -19,18 +18,17 @@ $settings.buildName:="TEST" $build:=cs.Build4D.CompiledProject.new($settings) -$destinationFolder:=Folder("/PACKAGE/Test"; *) -ASSERT($build.settings.buildName="TEST"; "(Current project) Wrong specified build name: "+$build.settings.buildName+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +ASSERT($build.settings.buildName="TEST"; "(Current project) Wrong specified build name: "+$build.settings.buildName+$link) $success:=$build.build() ASSERT($success; "(Current project) Compiled project build should success"+$link) -$compiledProject:=$destinationFolder.file("TEST.4DZ") +$compiledProject:=Folder("/PACKAGE/Test").file("TEST.4DZ") ASSERT($compiledProject.exists; "(Current project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -38,7 +36,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.CompiledProject.new($settings) -ASSERT($build.settings.buildName="TEST"; "(External project) Wrong specified build name: "+$build.settings.buildName+" (https://dev.azure.com/4dimension/4D/_workitems/edit/4736)") +ASSERT($build.settings.buildName="TEST"; "(External project) Wrong specified build name: "+$build.settings.buildName+$link) $success:=$build.build() @@ -47,4 +45,4 @@ ASSERT($success; "(External project) Compiled project build should success"+$lin ASSERT($compiledProject.exists; "(External project) Compiled project should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm index a407b9f..27560be 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5319.4dm @@ -30,7 +30,7 @@ $zip:=ZIP Read archive($compiledProject) ASSERT($zip=Null; "(Current project) Compiled project 4DZ file shouldn't be unzippable"+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -47,4 +47,4 @@ $zip:=ZIP Read archive($compiledProject) ASSERT($zip=Null; "(External project) Compiled project 4DZ file shouldn't be unzippable"+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm index 92a53d6..34795d2 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5321.4dm @@ -31,7 +31,7 @@ ASSERT($zip#Null; "(Current project) Compiled project 4DZ file should be unzippa $zip:=Null // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -49,4 +49,4 @@ ASSERT($zip#Null; "Compiled project 4DZ file should be unzippable"+$link) $zip:=Null // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm index 179b1a8..ca30c65 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3489_TC5322.4dm @@ -29,7 +29,7 @@ ASSERT($zip#Null; "(Current project) Compiled project 4DZ file should be unzippa $zip:=Null // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -47,4 +47,4 @@ ASSERT($zip#Null; "(External project) Compiled project 4DZ file should be unzipp $zip:=Null // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm index 5f63dca..dbef6df 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5331.4dm @@ -2,7 +2,7 @@ // Compile an application/component with good $settings.compilerOptions var $build : cs.Build4D.CompiledProject var $settings : Object -var $success : Variant +var $success : Boolean var $link : Text $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm index d3c5cdf..2bd3af0 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3490_TC5333.4dm @@ -2,7 +2,7 @@ // Compile an application/component with wrong $settings.compilerOptions var $build : cs.Build4D.CompiledProject var $settings : Object -var $success : Variant +var $success : Boolean var $link : Text $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm index dc3253e..43a0b4d 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5334.4dm @@ -27,7 +27,7 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(Current project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(External project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm index 75ee083..0dd4817 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5336.4dm @@ -27,7 +27,7 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists=False; "(Current project) Compiled project 4DZ file should not exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists=False; "(External project) Compiled project 4DZ file should not exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm index 3cfad7a..4d2b012 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_1_R3491_TC5337.4dm @@ -26,7 +26,7 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(Current project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -42,4 +42,4 @@ $compiledProject:=$build.settings.destinationFolder.file($build.settings.buildNa ASSERT($compiledProject.exists; "(External project) Compiled project 4DZ file should exist: "+$compiledProject.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm index d2f20a8..4a295f1 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3484_TC4725.4dm @@ -18,7 +18,7 @@ $settings.destinationFolder:="Test/" $build:=cs.Build4D.Component.new($settings) -$destinationFolder:=Folder("/PACKAGE/Test"; *).folder($build.settings.buildName+".4dbase/") +$destinationFolder:=Folder("/PACKAGE/Test").folder($build.settings.buildName+".4dbase/") ASSERT($build.settings.destinationFolder.platformPath=$destinationFolder.platformPath; "(Current project) Wrong custom destination folder: "+$build.settings.destinationFolder.platformPath+$link) $success:=$build.build() @@ -28,7 +28,7 @@ ASSERT($success; "(Current project) Component build should success"+$link) ASSERT($build.settings.destinationFolder.exists; "(Current project) Component should be placed in the custom destination folder: "+$build.settings.destinationFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($build.settings.destinationFolder.exists; "(External project) Component should be placed in the custom destination folder: "+$build.settings.destinationFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm index d07518d..c0ecf07 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4739.4dm @@ -41,7 +41,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -70,6 +70,6 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm index b0313ec..5317cc1 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4741.4dm @@ -42,7 +42,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -71,5 +71,5 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm index 1c53dd0..f09472b 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4745.4dm @@ -44,7 +44,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm index 513fb26..dd02363 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4746.4dm @@ -44,7 +44,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm index ddece27..6e9f8d8 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4747.4dm @@ -44,7 +44,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm index 55c6aaf..c551a77 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4750.4dm @@ -44,7 +44,7 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -73,6 +73,6 @@ If (Is macOS) End if // Cleanup build folder - Folder("/PACKAGE/Test"; *).delete(fk recursive) + Folder("/PACKAGE/Test").delete(fk recursive) End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm index f30a7ba..7d45ece 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5165.4dm @@ -30,7 +30,7 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation/") ASSERT($includedFolder.exists; "(Current project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -46,5 +46,5 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation/") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm index 2ee944f..2e026c9 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5167.4dm @@ -30,7 +30,7 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -46,5 +46,5 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm index c732e80..1d7c098 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5169.4dm @@ -30,7 +30,7 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation") ASSERT($includedFolder.exists; "(Current project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -50,4 +50,4 @@ $includedFolder:=$build.settings.destinationFolder.folder("Test/Documentation") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm index 20f2ef1..478dc69 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5170.4dm @@ -30,7 +30,7 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project // Filesystems are relative to the project executing the code, so they can not be resolved related to an external project \ No newline at end of file diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm index 5524a88..8e8ccfe 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5182.4dm @@ -30,7 +30,7 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -50,4 +50,4 @@ $includedFile:=$build.settings.destinationFolder.file("Test/README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm index fb180b9..c560328 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5183.4dm @@ -30,7 +30,7 @@ $includedFolder:=Folder(fk database folder; *).folder("Test/Documentation") ASSERT($includedFolder.exists; "(Current project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm index 7895c82..f495a09 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5184.4dm @@ -30,7 +30,7 @@ $includedFile:=Folder(fk database folder; *).file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm index 3bffddc..6476448 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5185.4dm @@ -30,7 +30,7 @@ $includedFolder:=Folder(fk database folder; *).folder("Test/Documentation") ASSERT($includedFolder.exists; "(Current project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm index 5a97f38..67867a4 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5186.4dm @@ -30,7 +30,7 @@ $includedFile:=Folder(fk database folder; *).file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ ASSERT($success; "(External project) Component build should success"+$link) ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm index 9265b98..c076aa0 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC5187.4dm @@ -30,7 +30,7 @@ $includedFile:=Folder(fk database folder; *).file("Test/README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project // Filesystems are relative to the project executing the code, so they can not be resolved related to an external project \ No newline at end of file diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm index 7f8c0f8..2aa31db 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6295.4dm @@ -29,7 +29,7 @@ $includedFolder:=$build.settings.destinationFolder.folder("Documentation/") ASSERT($includedFolder.exists; "(Current project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ $includedFolder:=$build.settings.destinationFolder.folder("Documentation/") ASSERT($includedFolder.exists; "(External project) Included folder should exist: "+$includedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm index 5659dec..1e91fc2 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3487_TC6296.4dm @@ -29,7 +29,7 @@ $includedFile:=$build.settings.destinationFolder.file("README.md") ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -45,4 +45,4 @@ $includedFile:=$build.settings.destinationFolder.file("README.md") ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm index 0255eed..858ee9e 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5311.4dm @@ -27,7 +27,7 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") ASSERT($deletedFile.exists=False; "(Current project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") ASSERT($deletedFile.exists=False; "(External project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm index 2d612b8..1fc1e61 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5313.4dm @@ -27,7 +27,7 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(Current project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(External project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm index b42aef4..c6d5afc 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5314.4dm @@ -27,7 +27,7 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/component.json") ASSERT($deletedFile.exists=False; "(Current project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") ASSERT($deletedFile.exists=False; "(External project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm index e410f5b..6d09a53 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3488_TC5315.4dm @@ -27,7 +27,7 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(Current project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) // MARK:- External project @@ -43,4 +43,4 @@ $deletedFolder:=$build.settings.destinationFolder.folder("Resources") ASSERT($deletedFolder.exists=False; "(External project) Deleted folder shouldn't exist: "+$deletedFolder.platformPath+$link) // Cleanup build folder -Folder("/PACKAGE/Test"; *).delete(fk recursive) +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm index 64fe454..a4cdbe4 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11162.4dm @@ -1 +1,50 @@ //%attributes = {} +// Test _build() function with the default name +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $standaloneApp : 4D.File +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build.settings.buildName=Storage.settings.projectName; "(Current project) Wrong default build name: "+$build.settings.buildName+$link) + +$success:=$build.build() + +ASSERT($success; "(Current project) Standalone build should success"+$link) + +$standaloneApp:=(Is macOS) ? Folder("/PACKAGE/Test/"+Storage.settings.projectName+".app") : Folder("/PACKAGE/Test/"+Storage.settings.projectName).file(Storage.settings.projectName+".exe") +ASSERT($standaloneApp.exists; "(Current project) Standalone should exist: "+$standaloneApp.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build.settings.buildName=Storage.settings.externalProjectName; "(External project) Wrong default build name: "+$build.settings.buildName+$link) + +$success:=$build.build() + +ASSERT($success; "(External project) Standalone build should success"+$link) + +$standaloneApp:=(Is macOS) ? Folder("/PACKAGE/Test/"+Storage.settings.externalProjectName+".app") : Folder("/PACKAGE/Test/"+Storage.settings.externalProjectName).file(Storage.settings.externalProjectName+".exe") +ASSERT($standaloneApp.exists; "(External project) Standalone should exist: "+$standaloneApp.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11164.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11164.4dm new file mode 100644 index 0000000..a09e7e6 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11077_TC11164.4dm @@ -0,0 +1,51 @@ +//%attributes = {} +// Test _build() function with a specific name +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $standaloneApp : 4D.File +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.buildName:="TEST" + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build.settings.buildName="TEST"; "(Current project) Wrong specified build name: "+$build.settings.buildName+$link) + +$success:=$build.build() + +ASSERT($success; "(Current project) Standalone build should success"+$link) + +$standaloneApp:=(Is macOS) ? Folder("/PACKAGE/Test/TEST.app") : File("/PACKAGE/Test/TEST/TEST.exe") +ASSERT($standaloneApp.exists; "(Current project) Standalone should exist: "+$standaloneApp.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build.settings.buildName="TEST"; "(External project) Wrong specified build name: "+$build.settings.buildName+$link) + +$success:=$build.build() + +ASSERT($success; "(External project) Standalone build should success"+$link) + +$standaloneApp:=(Is macOS) ? Folder("/PACKAGE/Test/TEST.app") : File("/PACKAGE/Test/TEST/TEST.exe") +ASSERT($standaloneApp.exists; "(External project) Standalone should exist: "+$standaloneApp.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm new file mode 100644 index 0000000..3e1eb3d --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm @@ -0,0 +1,69 @@ +//%attributes = {} +// Define a wrong path of the Volume Desktop application +var $build : cs.Build4D.Standalone +var $settings : Object +var $success; $found : Boolean +var $link : Text +var $log : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=Folder("/PACKAGE/") + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application folder checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(Current project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(Current project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application folder checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(External project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(External project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm new file mode 100644 index 0000000..627acd8 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm @@ -0,0 +1,68 @@ +//%attributes = {} +// Not define any path of Volume Desktop application +var $build : cs.Build4D.Standalone +var $settings : Object +var $success; $found : Boolean +var $link : Text +var $log : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application folder checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(Current project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(Current project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) + +$found:=False +For each ($log; $build.logs) + If ($log.function="Source application folder checking") + If ($log.severity=2) + $found:=True + break + End if + End if +End for each + +ASSERT($found; "(External project) Standalone build should generate an error"+$link) + +$success:=$build.build() + +ASSERT($success=False; "(External project) Standalone build should fail"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm new file mode 100644 index 0000000..1ec101e --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm @@ -0,0 +1,65 @@ +//%attributes = {} +// Define the version application information +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $infoFile : 4D.File +var $infos : Object + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.versioning:=New object +$settings.versioning.version:="UT_version" +$settings.versioning.copyright:="UT_copyright" +$settings.versioning.companyName:="UT_companyName" +$settings.versioning.fileDescription:="UT_fileDescription" +$settings.versioning.internalName:="UT_internalName" + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +If (Is macOS) + $infoFile:=$build.settings.destinationFolder.file("Contents/Info.plist") + $infos:=$infoFile.getAppInfo() + ASSERT($infos.CFBundleVersion="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.CFBundleShortVersionString="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.NSHumanReadableCopyright="UT_copyright"; "(Current project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") + ASSERT($infos.CFBundleIdentifier="UT_companyName@"; "(Current project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") +Else + $infoFile:=This.settings.destinationFolder.file("Resources/Info.plist") + $infos:=$infoFile.getAppInfo() + +End if + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +If (Is macOS) + $infoFile:=$build.settings.destinationFolder.file("Contents/Info.plist") + $infos:=$infoFile.getAppInfo() + ASSERT($infos.CFBundleVersion="UT_version"; "(External project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.CFBundleShortVersionString="UT_version"; "(External project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.NSHumanReadableCopyright="UT_copyright"; "(External project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") + ASSERT($infos.CFBundleIdentifier="UT_companyName@"; "(External project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") +Else + $infoFile:=This.settings.destinationFolder.file("Resources/Info.plist") + $infos:=$infoFile.getAppInfo() + +End if + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm new file mode 100644 index 0000000..84c0103 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Define the data linking mode as By application name +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $infoFile : 4D.File +var $infos : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.versioning:=New object +$settings.lastDataPathLookup:="ByAppName" + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm new file mode 100644 index 0000000..b3ddcf3 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Define the data linking mode as By application path +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $infoFile : 4D.File +var $infos : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.versioning:=New object +$settings.lastDataPathLookup:="ByAppPath" + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppPath"; "(Current project) Standalone lastDataPathLookup should be set to ByAppPath"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppPath"; "(External project) Standalone lastDataPathLookup should be set to ByAppPath"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm new file mode 100644 index 0000000..b979dc0 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Define the data linking mode as other value than By application name or application path +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $infoFile : 4D.File +var $infos : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.versioning:=New object +$settings.lastDataPathLookup:="AnotherValue" + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm new file mode 100644 index 0000000..f92b675 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm @@ -0,0 +1,44 @@ +//%attributes = {} +// Define the data linking mode as By application name +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $infoFile : 4D.File +var $infos : Object + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.versioning:=New object + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infos:=$infoFile.getAppInfo() +ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/folders.json b/Build4D_UnitTests/Project/Sources/folders.json index 697d0e6..7a5049e 100644 --- a/Build4D_UnitTests/Project/Sources/folders.json +++ b/Build4D_UnitTests/Project/Sources/folders.json @@ -73,20 +73,75 @@ }, "3_R11077": { "methods": [ - "ut_3_R11077_TC11162" + "ut_3_R11077_TC11162", + "ut_3_R11077_TC11164" ] }, - "Default Classes": {}, - "Default Folder": { + "3_R11078": { + "methods": [ + "ut_3_R11078_TC11169", + "ut_3_R11078_TC11170" + ] + }, + "3_R11079": { + "methods": [ + "mut_3_R11079_TC11171" + ] + }, + "3_R11080": {}, + "3_R11081": { + "methods": [ + "ut_3_R11081_TC" + ] + }, + "3_R11083": { + "methods": [ + "ut_3_R11083_TC11190", + "ut_3_R11083_TC11192", + "ut_3_R11083_TC11958" + ] + }, + "3_R11084": { + "methods": [ + "ut_3_R11084_TC11200" + ] + }, + "CompiledProject": { + "groups": [ + "1_R3485", + "1_R3489", + "1_R3490", + "1_R3491" + ], + "methods": [ + "runUnitTests1" + ] + }, + "Component": { + "groups": [ + "2_R3484", + "2_R3486", + "2_R3487", + "2_R3488" + ], + "methods": [ + "runUnitTests2" + ] + }, + "Standalone": { "groups": [ - "Default Classes", - "Default Forms", - "Default Project Methods", - "Default Tables" + "3_R11077", + "3_R11078", + "3_R11079", + "3_R11080", + "3_R11081", + "3_R11083", + "3_R11084" + ], + "methods": [ + "runUnitTests3", + "zzzStandalone" ] }, - "Default Forms": {}, - "Default Project Methods": {}, - "Default Tables": {}, "trash": {} } \ No newline at end of file diff --git a/Build4D_UnitTests/Settings/UT_Settings.json b/Build4D_UnitTests/Settings/UT_Settings.json new file mode 100644 index 0000000..d7bf617 --- /dev/null +++ b/Build4D_UnitTests/Settings/UT_Settings.json @@ -0,0 +1,5 @@ +{ + "licenseUUD":"/PACKAGE/Settings/4UUD.license4D", + "macVolumeDesktop":"/Applications/4D v0.0/4D Volume Desktop.app/", + "winVolumeDesktop":"C:/Program Files/4D/4D v0.0/4D Volume Desktop/" +} \ No newline at end of file From c6a671fe6999f6bcfa7dca6477056d2c6d0a1087 Mon Sep 17 00:00:00 2001 From: Dev14D Date: Tue, 27 Jun 2023 16:34:54 +0200 Subject: [PATCH 19/29] Update example in the Standalone doc --- Build4D/Documentation/Classes/Standalone.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index 77fbb22..fd2c0dc 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -94,7 +94,7 @@ $settings.startElevated:=False $settings.lastDataPathLookup:="ByAppPath" // Define 4D Volume Desktop path -$settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app").path +$settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app") // Delete unneccessary module $settings.excludeModules:=New collection("CEF"; "MeCab") @@ -112,16 +112,12 @@ $settings.iconPath:="/RESOURCES/myIcon.icns" // Add the application information $settings.versioning:=New object -$settings.versioning.version:="myBuild4D_version" -$settings.versioning.copyright:="myBuild4D_copyright" -$settings.versioning.creator:="myBuild4D_creator" -$settings.versioning.comment:="myBuild4D_comment" -$settings.versioning.companyName:="myBuild4D_companyName" -$settings.versioning.fileDescription:="myBuild4D_fileDescription" -$settings.versioning.internalName:="myBuild4D_internalName" +$settings.versioning.version:="version" +$settings.versioning.copyright:="copyright" +$settings.versioning.companyName:="companyName" // Create the deployment license file -$settings.license:=Folder(fk licenses folder).file("XXXXX.license4D").path +$settings.license:=Folder(fk licenses folder).file("XXXXX.license4D") // Sign the macOS appplication $settings.signApplication:=New object From 9e43fe569b603324d06e9211e51cd61b998c201f Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Tue, 27 Jun 2023 22:23:00 +0200 Subject: [PATCH 20/29] Unit Tests --- .../Project/Sources/Classes/Standalone.4dm | 2 + Build4D/Project/Sources/Classes/_core.4dm | 6 +- Build4D/Project/Sources/settings.4DSettings | 2 +- Build4D/Resources/CompiledProject.json | 2 +- Build4D/Resources/Component.json | 2 +- Build4D/Resources/Standalone.json | 2 +- .../Sources/Methods/mut_2_R3486_TC4743.4dm | 2 +- .../Sources/Methods/mut_2_R3486_TC4749.4dm | 2 +- .../Sources/Methods/mut_3_R11086_TC11488.4dm | 46 +++++++++++ .../Sources/Methods/mut_3_R11087_TC11217.4dm | 78 +++++++++++++++++++ .../Sources/Methods/ut_2_R3486_TC4737.4dm | 1 - .../Sources/Methods/ut_3_R11078_TC11169.4dm | 31 ++------ .../Sources/Methods/ut_3_R11078_TC11170.4dm | 31 ++------ ...79_TC11171.4dm => ut_3_R11079_TC11171.4dm} | 33 +++----- .../Sources/Methods/ut_3_R11081_TC.4dm | 36 +++++++-- .../Sources/Methods/ut_3_R11083_TC11190.4dm | 5 +- .../Sources/Methods/ut_3_R11083_TC11192.4dm | 5 +- .../Sources/Methods/ut_3_R11083_TC11958.4dm | 5 +- .../Sources/Methods/ut_3_R11084_TC11200.4dm | 7 +- .../Sources/Methods/ut_3_R11085_TC11204.4dm | 48 ++++++++++++ .../Sources/Methods/ut_3_R11085_TC11206.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11087_TC11207.4dm | 65 ++++++++++++++++ .../Sources/Methods/ut_3_R11088_TC11220.4dm | 48 ++++++++++++ .../Sources/Methods/ut_3_R11089_TC11233.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11090_TC12455.4dm | 51 ++++++++++++ .../Sources/Methods/ut_3_R11090_TC12456.4dm | 51 ++++++++++++ .../Sources/Methods/ut_3_R11090_TC12457.4dm | 50 ++++++++++++ .../Sources/Methods/ut_3_R11092_TC11241.4dm | 22 ++++++ .../Sources/Methods/ut_3_R11094_TC11250.4dm | 30 +++++++ .../Sources/Methods/ut_3_R11095_TC11481.4dm | 45 +++++++++++ .../Sources/Methods/ut_3_R11097_TC11483.4dm | 46 +++++++++++ .../Sources/Methods/ut_3_R11097_TC11485.4dm | 46 +++++++++++ .../Project/Sources/folders.json | 74 ++++++++++++++++-- Build4D_UnitTests/Resources/UnitTests.txt | 1 + Build4D_UnitTests/Settings/UT_Settings.json | 8 +- 35 files changed, 866 insertions(+), 107 deletions(-) create mode 100644 Build4D_UnitTests/Project/Sources/Methods/mut_3_R11086_TC11488.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/mut_3_R11087_TC11217.4dm rename Build4D_UnitTests/Project/Sources/Methods/{mut_3_R11079_TC11171.4dm => ut_3_R11079_TC11171.4dm} (69%) create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11204.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11206.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11087_TC11207.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11088_TC11220.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11089_TC11233.4dm create mode 100755 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12455.4dm create mode 100755 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12456.4dm create mode 100755 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12457.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11092_TC11241.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11094_TC11250.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11095_TC11481.4dm create mode 100644 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11483.4dm create mode 100755 Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11485.4dm diff --git a/Build4D/Project/Sources/Classes/Standalone.4dm b/Build4D/Project/Sources/Classes/Standalone.4dm index 73a6c77..59884f5 100644 --- a/Build4D/Project/Sources/Classes/Standalone.4dm +++ b/Build4D/Project/Sources/Classes/Standalone.4dm @@ -41,6 +41,7 @@ Class constructor($customSettings : Object) "severity"; Error message)) Else If (Not(This.settings.sourceAppFolder.exists)) + This._validInstance:=False This._log(New object(\ "function"; "Source application folder checking"; \ "message"; "Source application folder doesn't exist"; \ @@ -49,6 +50,7 @@ Class constructor($customSettings : Object) Else $fileCheck:=(Is macOS) ? This.settings.sourceAppFolder.file("Contents/MacOS/4D Volume Desktop").exists : This.settings.sourceAppFolder.file("4D Volume Desktop.4DE").exists If (Not($fileCheck)) + This._validInstance:=False This._log(New object(\ "function"; "Source application folder checking"; \ "message"; "Source application is not a 4D Volume Desktop"; \ diff --git a/Build4D/Project/Sources/Classes/_core.4dm b/Build4D/Project/Sources/Classes/_core.4dm index 01ef858..12754d5 100644 --- a/Build4D/Project/Sources/Classes/_core.4dm +++ b/Build4D/Project/Sources/Classes/_core.4dm @@ -513,6 +513,7 @@ Function _setAppOptions() : Boolean Else // Windows If (This.settings.versioning.version#Null) $exeInfo.ProductVersion:=This.settings.versioning.version + $exeInfo.FileVersion:=This.settings.versioning.version End if If (This.settings.versioning.copyright#Null) $exeInfo.LegalCopyright:=This.settings.versioning.copyright @@ -534,6 +535,7 @@ Function _setAppOptions() : Boolean If ($exeInfo#Null) $exeFile:=This.settings.destinationFolder.file(This.settings.buildName+".exe") If ($exeFile.exists) + $exeInfo.OriginalFilename:=$exeFile.fullName $exeFile.setAppInfo($exeInfo) Else This._log(New object(\ @@ -552,7 +554,7 @@ Function _setAppOptions() : Boolean return False End if - If (Is Windows) + If (Is Windows) // Updater elevation rights $manifestFile:=((This.settings.startElevated#Null) && (This.settings.startElevated))\ ? This.settings.destinationFolder.file("Resources/Updater/elevated.manifest")\ : This.settings.destinationFolder.file("Resources/Updater/normal.manifest") @@ -602,7 +604,7 @@ Function _sign() : Boolean var $commandLine; $certificateName : Text var $signatureWorker : 4D.SystemWorker - $certificateName:=(Not(This.settings.signApplication.macSignature) && This.settings.signApplication.adHocSignature) ? "-" : This.settings.signApplication.macCertificate // If nAdHocSignature, the certificate name shall be '-' + $certificateName:=(Not(This.settings.signApplication.macSignature) && This.settings.signApplication.adHocSignature) ? "-" : This.settings.signApplication.macCertificate // If AdHocSignature, the certificate name shall be '-' If ($certificateName#"") diff --git a/Build4D/Project/Sources/settings.4DSettings b/Build4D/Project/Sources/settings.4DSettings index 68d866b..8653716 100644 --- a/Build4D/Project/Sources/settings.4DSettings +++ b/Build4D/Project/Sources/settings.4DSettings @@ -1,4 +1,4 @@ - + diff --git a/Build4D/Resources/CompiledProject.json b/Build4D/Resources/CompiledProject.json index 8d791ca..e5c9852 100644 --- a/Build4D/Resources/CompiledProject.json +++ b/Build4D/Resources/CompiledProject.json @@ -1,7 +1,7 @@ { "//target":"CompiledProject", "packedProject":true, - "obfuscated4DZ":false, + "obfuscated":false, "includePaths":[], "deletePaths":[] } diff --git a/Build4D/Resources/Component.json b/Build4D/Resources/Component.json index 8c3b7cd..31e2cf0 100644 --- a/Build4D/Resources/Component.json +++ b/Build4D/Resources/Component.json @@ -1,7 +1,7 @@ { "//target":"Component", "packedProject":true, - "obfuscated4DZ":false, + "obfuscated":false, "includePaths": [ { diff --git a/Build4D/Resources/Standalone.json b/Build4D/Resources/Standalone.json index cc26e13..4fcd66a 100644 --- a/Build4D/Resources/Standalone.json +++ b/Build4D/Resources/Standalone.json @@ -1,7 +1,7 @@ { "//target":"Standalone", "packedProject":true, - "obfuscated4DZ":false, + "obfuscated":false, "lastDataPathLookup":"ByAppName", "includePaths": [ diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm index 5272669..79776b3 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4743.4dm @@ -23,7 +23,7 @@ If (Is macOS) $settings.compilerOptions:=New object("targets"; New collection("x86_64_generic"; "arm64_macOS_lib")) // Silicon compilation mandatory, else no code to sign, so can't check requested result $settings.signApplication:=New object(\ "macSignature"; True; \ - "macCertificate"; "Damien FUZEAU") + "macCertificate"; Storage.settings.macCertificate) $build:=cs.Build4D.Component.new($settings) diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm index 080c6ec..4a60354 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_2_R3486_TC4749.4dm @@ -23,7 +23,7 @@ If (Is macOS) $settings.compilerOptions:=New object("targets"; New collection("x86_64_generic"; "arm64_macOS_lib")) // Silicon compilation mandatory, else no code to sign, so can't check requested result $settings.signApplication:=New object(\ "macSignature"; True; \ - "macCertificate"; "Damien FUZEAU"; \ + "macCertificate"; Storage.settings.macCertificate; \ "adHocSignature"; False) $build:=cs.Build4D.Component.new($settings) diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11086_TC11488.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11086_TC11488.4dm new file mode 100644 index 0000000..0594d24 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11086_TC11488.4dm @@ -0,0 +1,46 @@ +//%attributes = {} +// Define an icon +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $link : Text +var $assertions : Boolean +var $log : Variant + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +$assertions:=Get assert enabled +SET ASSERT ENABLED(True) + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.iconPath:=(Is macOS) ? File("/PACKAGE/Build4D.icns") : File("/PACKAGE/Build4D.ico") + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() +TRACE +// Check icon + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() +TRACE +// Check icon + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +SET ASSERT ENABLED($assertions) diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11087_TC11217.4dm b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11087_TC11217.4dm new file mode 100644 index 0000000..58195ff --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11087_TC11217.4dm @@ -0,0 +1,78 @@ +//%attributes = {} +// Test application signature with certificate +If (Is macOS) + var $build : cs.Build4D.Standalone + var $settings : Object + var $success : Boolean + var $link : Text + var $assertions : Boolean + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + $assertions:=Get assert enabled + SET ASSERT ENABLED(True) + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.compilerOptions:=New object("targets"; New collection("x86_64_generic"; "arm64_macOS_lib")) + $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + $settings.signApplication:=New object(\ + "macSignature"; True; \ + "macCertificate"; Storage.settings.macCertificate; \ + "adHocSignature"; False) + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(Current project) Standalone build should success"+$link) + + var $verificationWorker : 4D.SystemWorker + $verificationWorker:=4D.SystemWorker.new("codesign -dv --verbose=4 "+$build.settings.destinationFolder.path) + $verificationWorker.wait(120) + If ($verificationWorker.terminated) + If ($verificationWorker.exitCode=0) + // The application is signed with certificate if a line "Authority=certificate name" exists + var $lines : Collection + $lines:=Split string($verificationWorker.responseError; "\n") + ASSERT(Not(Undefined($lines.find(Formula($1.value=$2); "Authority="+Storage.settings.macCertificate))); "(Current project) Standalone should be signed. Verification response: "+$verificationWorker.responseError+$link) + End if + End if + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(External project) Standalone build should success"+$link) + + var $verificationWorker : 4D.SystemWorker + $verificationWorker:=4D.SystemWorker.new("codesign -dv --verbose=4 "+$build.settings.destinationFolder.path) + $verificationWorker.wait(120) + If ($verificationWorker.terminated) + If ($verificationWorker.exitCode=0) + // The application is signed with certificate if a line "Authority=certificate name" exists + var $lines : Collection + $lines:=New collection() + $lines:=Split string($verificationWorker.responseError; "\n") + ASSERT(Not(Undefined($lines.find(Formula($1.value=$2); "Authority="+Storage.settings.macCertificate))); "(External project) Standalone should be signed. Verification response: "+$verificationWorker.responseError+$link) + End if + End if + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + SET ASSERT ENABLED($assertions) + +Else + ALERT("macOS only!") +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm index 1402bbe..6f406eb 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_2_R3486_TC4737.4dm @@ -18,7 +18,6 @@ If (Is macOS) $settings.compilerOptions:=New object("targets"; New collection("x86_64_generic"; "arm64_macOS_lib")) // Silicon compilation mandatory, else no code to sign, so can't check requested result $build:=cs.Build4D.Component.new($settings) - $success:=$build.build() ASSERT($success; "(Current project) Component build should success"+$link) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm index 3e1eb3d..01c06a0 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11169.4dm @@ -2,9 +2,9 @@ // Define a wrong path of the Volume Desktop application var $build : cs.Build4D.Standalone var $settings : Object -var $success; $found : Boolean +var $success : Boolean var $link : Text -var $log : Object +var $log : Variant $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" @@ -22,17 +22,9 @@ $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application folder checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application folder checking") -ASSERT($found; "(Current project) Standalone build should generate an error"+$link) +ASSERT((($log#Null) && ($log.severity=Error message)); "(Current project) Standalone build should generate an error"+$link) $success:=$build.build() @@ -49,17 +41,10 @@ $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application folder checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each - -ASSERT($found; "(External project) Standalone build should generate an error"+$link) +$log:=Null +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application folder checking") + +ASSERT((($log#Null) && ($log.severity=Error message)); "(External project) Standalone build should generate an error"+$link) $success:=$build.build() diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm index 627acd8..6e411b2 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11078_TC11170.4dm @@ -2,9 +2,9 @@ // Not define any path of Volume Desktop application var $build : cs.Build4D.Standalone var $settings : Object -var $success; $found : Boolean +var $success : Boolean var $link : Text -var $log : Object +var $log : Variant $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" @@ -21,17 +21,9 @@ $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application folder checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application folder checking") -ASSERT($found; "(Current project) Standalone build should generate an error"+$link) +ASSERT((($log#Null) && ($log.severity=Error message)); "(Current project) Standalone build should generate an error"+$link) $success:=$build.build() @@ -48,17 +40,10 @@ $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application folder checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each - -ASSERT($found; "(External project) Standalone build should generate an error"+$link) +$log:=Null +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application folder checking") + +ASSERT((($log#Null) && ($log.severity=Error message)); "(External project) Standalone build should generate an error"+$link) $success:=$build.build() diff --git a/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11079_TC11171.4dm similarity index 69% rename from Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm rename to Build4D_UnitTests/Project/Sources/Methods/ut_3_R11079_TC11171.4dm index 653921c..5272f74 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/mut_3_R11079_TC11171.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11079_TC11171.4dm @@ -2,10 +2,10 @@ // Define a 4D Volume Desktop with the version number is not match the 4D Developer Edition version number var $build : cs.Build4D.Standalone var $settings : Object -var $success; $found : Boolean +var $success : Boolean var $link : Text -var $log : Object var $assertions : Boolean +var $log : Variant $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" @@ -20,23 +20,15 @@ $settings:=New object() $settings.formulaForLogs:=Formula(logGitHubActions($1)) $settings.destinationFolder:="./Test/" $settings.license:=Storage.settings.licenseUUD -$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.invalid_macVolumeDesktop) : Folder(Storage.settings.invalid_winVolumeDesktop) $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(Current project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application version checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application version checking") -ASSERT($found; "(Current project) Standalone build should generate an error"+$link) +ASSERT((($log#Null) && ($log.severity=Error message)); "(Current project) Standalone build should generate an error"+$link) $success:=$build.build() @@ -53,17 +45,10 @@ $build:=cs.Build4D.Standalone.new($settings) ASSERT($build._validInstance=False; "(External project) Object instance shouldn't be valid"+$link) -$found:=False -For each ($log; $build.logs) - If ($log.function="Source application version checking") - If ($log.severity=2) - $found:=True - break - End if - End if -End for each - -ASSERT($found; "(External project) Standalone build should generate an error"+$link) +$log:=Null +$log:=$build.logs.find(Formula($1.value.function=$2); "Source application version checking") + +ASSERT((($log#Null) && ($log.severity=Error message)); "(External project) Standalone build should generate an error"+$link) $success:=$build.build() diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm index 1ec101e..92b667b 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11081_TC.4dm @@ -3,7 +3,7 @@ var $build : cs.Build4D.Standalone var $settings : Object var $success : Boolean -var $infoFile : 4D.File +var $infoFile; $exeFile : 4D.File var $infos : Object logGitHubActions(Current method name) @@ -33,9 +33,20 @@ If (Is macOS) ASSERT($infos.NSHumanReadableCopyright="UT_copyright"; "(Current project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") ASSERT($infos.CFBundleIdentifier="UT_companyName@"; "(Current project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") Else - $infoFile:=This.settings.destinationFolder.file("Resources/Info.plist") - $infos:=$infoFile.getAppInfo() - + $exeFile:=$build.settings.destinationFolder.file($build.settings.buildName+".exe") + If ($exeFile.exists) + $infos:=$exeFile.getAppInfo() + ASSERT($infos.FileVersion="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.ProductVersion="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.LegalCopyright="UT_copyright"; "(Current project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") + ASSERT($infos.CompanyName="UT_companyName"; "(Current project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") + ASSERT($infos.FileDescription="UT_fileDescription"; "(Current project) Standalone fileDescription should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11185") + ASSERT($infos.InternalName="UT_internalName"; "(Current project) Standalone internalName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11186") + ASSERT($infos.OriginalFilename=$exeFile.fullName; "(Current project) Standalone OriginalFilename should be set") + ASSERT($infos.ProductName=$build.settings.buildName; "(Current project) Standalone ProductName should be set") + Else + ASSERT(False; "(Current project) Standalone exe file does not exist:"+$exeFile.path) + End if End if // Cleanup build folder @@ -56,9 +67,20 @@ If (Is macOS) ASSERT($infos.NSHumanReadableCopyright="UT_copyright"; "(External project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") ASSERT($infos.CFBundleIdentifier="UT_companyName@"; "(External project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") Else - $infoFile:=This.settings.destinationFolder.file("Resources/Info.plist") - $infos:=$infoFile.getAppInfo() - + $exeFile:=$build.settings.destinationFolder.file($build.settings.buildName+".exe") + If ($exeFile.exists) + $infos:=$exeFile.getAppInfo() + ASSERT($infos.FileVersion="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.ProductVersion="UT_version"; "(Current project) Standalone version should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11179") + ASSERT($infos.LegalCopyright="UT_copyright"; "(Current project) Standalone copyright should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11181") + ASSERT($infos.CompanyName="UT_companyName"; "(Current project) Standalone companyName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11184") + ASSERT($infos.FileDescription="UT_fileDescription"; "(Current project) Standalone fileDescription should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11185") + ASSERT($infos.InternalName="UT_internalName"; "(Current project) Standalone internalName should be set (https://dev.azure.com/4dimension/4D/_workitems/edit/11186") + ASSERT($infos.OriginalFilename=$exeFile.fullName; "(Current project) Standalone OriginalFilename should be set") + ASSERT($infos.ProductName=$build.settings.buildName; "(Current project) Standalone ProductName should be set") + Else + ASSERT(False; "(Current project) Standalone exe file does not exist:"+$exeFile.path) + End if End if // Cleanup build folder diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm index 84c0103..ce2833e 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11190.4dm @@ -17,13 +17,12 @@ $settings.formulaForLogs:=Formula(logGitHubActions($1)) $settings.destinationFolder:="./Test/" $settings.license:=Storage.settings.licenseUUD $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) -$settings.versioning:=New object $settings.lastDataPathLookup:="ByAppName" $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) @@ -37,7 +36,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm index b3ddcf3..700811d 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11192.4dm @@ -17,13 +17,12 @@ $settings.formulaForLogs:=Formula(logGitHubActions($1)) $settings.destinationFolder:="./Test/" $settings.license:=Storage.settings.licenseUUD $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) -$settings.versioning:=New object $settings.lastDataPathLookup:="ByAppPath" $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppPath"; "(Current project) Standalone lastDataPathLookup should be set to ByAppPath"+$link) @@ -37,7 +36,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppPath"; "(External project) Standalone lastDataPathLookup should be set to ByAppPath"+$link) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm index b979dc0..26768c2 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11083_TC11958.4dm @@ -17,13 +17,12 @@ $settings.formulaForLogs:=Formula(logGitHubActions($1)) $settings.destinationFolder:="./Test/" $settings.license:=Storage.settings.licenseUUD $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) -$settings.versioning:=New object $settings.lastDataPathLookup:="AnotherValue" $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) @@ -37,7 +36,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm index f92b675..22133d0 100644 --- a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11084_TC11200.4dm @@ -1,5 +1,5 @@ //%attributes = {} -// Define the data linking mode as By application name +// Don't define the data linking mode var $build : cs.Build4D.Standalone var $settings : Object var $success : Boolean @@ -17,12 +17,11 @@ $settings.formulaForLogs:=Formula(logGitHubActions($1)) $settings.destinationFolder:="./Test/" $settings.license:=Storage.settings.licenseUUD $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) -$settings.versioning:=New object $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(Current project) Standalone lastDataPathLookup should be set to byAppName"+$link) @@ -36,7 +35,7 @@ $settings.projectFile:=Storage.settings.externalProjectFile $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() -$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : This.settings.destinationFolder.file("Resources/Info.plist") +$infoFile:=(Is macOS) ? $build.settings.destinationFolder.file("Contents/Info.plist") : $build.settings.destinationFolder.file("Resources/Info.plist") $infos:=$infoFile.getAppInfo() ASSERT($infos["com.4D.BuildApp.LastDataPathLookup"]="ByAppName"; "(External project) Standalone lastDataPathLookup should be set to byAppName"+$link) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11204.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11204.4dm new file mode 100644 index 0000000..4b8da67 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11204.4dm @@ -0,0 +1,48 @@ +//%attributes = {} +// Define an invalid licence +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $link : Text +var $log : Variant + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.invalid_LicenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success=False; "(Current project) Standalone build should fail with invalid license"+$link) + +$log:=$build.logs.find(Formula($1.value.function=$2); "Deployment license creation") + +ASSERT((($log#Null) && ($log.severity=Error message)); "(Current project) Standalone license error should be logged"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success=False; "(External project) Standalone build should fail with invalid license"+$link) + +$log:=Null +$log:=$build.logs.find(Formula($1.value.function=$2); "Deployment license creation") + +ASSERT((($log#Null) && ($log.severity=Error message)); "(External project) Standalone license error should be logged"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11206.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11206.4dm new file mode 100644 index 0000000..a67372c --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11085_TC11206.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Build without any licence +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $link : Text +var $log : Variant + +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success=False; "(Current project) Standalone build should fail without any license"+$link) + +$log:=$build.logs.find(Formula($1.value.function=$2); "License file checking") +ASSERT((($log#Null) && ($log.severity=Error message)); "(Current project) Standalone license error should be logged"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success=False; "(External project) Standalone build should fail without any license"+$link) + +$log:=Null +$log:=$build.logs.find(Formula($1.value.function=$2); "License file checking") +ASSERT((($log#Null) && ($log.severity=Error message)); "(External project) Standalone license error should be logged"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11087_TC11207.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11087_TC11207.4dm new file mode 100644 index 0000000..6f3e188 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11087_TC11207.4dm @@ -0,0 +1,65 @@ +//%attributes = {} +// Test application adhoc signature +If (Is macOS) + var $build : cs.Build4D.Standalone + var $settings : Object + var $success : Boolean + var $link : Text + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.compilerOptions:=New object("targets"; New collection("x86_64_generic"; "arm64_macOS_lib")) + $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(Current project) Standalone build should success"+$link) + + var $verificationWorker : 4D.SystemWorker + $verificationWorker:=4D.SystemWorker.new("codesign -dv --verbose=4 "+$build.settings.destinationFolder.path) + $verificationWorker.wait(120) + If ($verificationWorker.terminated) + If ($verificationWorker.exitCode=0) + // The application is signed adhoc if a line "Signature=adhoc" exists + var $lines : Collection + $lines:=Split string($verificationWorker.responseError; "\n") + ASSERT(Not(Undefined($lines.find(Formula($1.value=$2); "Signature=adhoc"))); "(Current project) Standalone should be signed. Verification response: "+$verificationWorker.responseError+$link) + End if + End if + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(External project) Standalone build should success"+$link) + + var $verificationWorker : 4D.SystemWorker + $verificationWorker:=4D.SystemWorker.new("codesign -dv --verbose=4 "+$build.settings.destinationFolder.path) + $verificationWorker.wait(120) + If ($verificationWorker.terminated) + If ($verificationWorker.exitCode=0) + // The application is signed adhoc if a line "Signature=adhoc" exists + var $lines : Collection + $lines:=New collection() + $lines:=Split string($verificationWorker.responseError; "\n") + ASSERT(Not(Undefined($lines.find(Formula($1.value=$2); "Signature=adhoc"))); "(External project) Standalone should be signed. Verification response: "+$verificationWorker.responseError+$link) + End if + End if + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11088_TC11220.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11088_TC11220.4dm new file mode 100644 index 0000000..d06a3b0 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11088_TC11220.4dm @@ -0,0 +1,48 @@ +//%attributes = {} +// Add a file located at a relative path to a destination located at a relative path +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $includedFile : 4D.File +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.includePaths:=New collection(New object(\ +"source"; "./README.md"; \ +"destination"; "./Test/")\ +) + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(Current project) Standalone build should success"+$link) + +$includedFile:=$build._structureFolder.file("Test/README.md") +ASSERT($includedFile.exists; "(Current project) Included file should exist: "+$includedFile.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(External project) Standalone build should success"+$link) + +$includedFile:=$build._structureFolder.file("Test/README.md") +ASSERT($includedFile.exists; "(External project) Included file should exist: "+$includedFile.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11089_TC11233.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11089_TC11233.4dm new file mode 100644 index 0000000..a1c64e2 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11089_TC11233.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Remove a file located at a relative path +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $deletedFile : 4D.File +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.deletePaths:=New collection("./Resources/UnitTests.txt") + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(Current project) Standalone build should success"+$link) + +$deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") +ASSERT($deletedFile.exists=False; "(Current project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(External project) Standalone build should success"+$link) + +$deletedFile:=$build.settings.destinationFolder.file("Resources/UnitTests.txt") +ASSERT($deletedFile.exists=False; "(Current project) Deleted file shouldn't exist: "+$deletedFile.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12455.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12455.4dm new file mode 100755 index 0000000..af57677 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12455.4dm @@ -0,0 +1,51 @@ +//%attributes = {} +// Check the custom elevation right for the Updater (normal) +If (Is Windows) // Only on Windows + + var $build : cs.Build4D.Standalone + var $settings : Object + var $success : Boolean + var $manifestFile : 4D.File + var $manifestContent : Text + + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.sourceAppFolder:=Folder(Storage.settings.winVolumeDesktop) + $settings.startElevated:=False + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(Current project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"asInvoker\"@"; "(Current project) Standalone Updater manifest should contain normal rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(External project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"asInvoker\"@"; "(External project) Standalone Updater manifest should contain normal rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12456.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12456.4dm new file mode 100755 index 0000000..a60b67e --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12456.4dm @@ -0,0 +1,51 @@ +//%attributes = {} +// Check the custom elevation right for the Updater (elevated) +If (Is Windows) // Only on Windows + + var $build : cs.Build4D.Standalone + var $settings : Object + var $success : Boolean + var $manifestFile : 4D.File + var $manifestContent : Text + + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.sourceAppFolder:=Folder(Storage.settings.winVolumeDesktop) + $settings.startElevated:=True + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(Current project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"requireAdministrator\"@"; "(Current project) Standalone Updater manifest should contain elevated rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(External project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"requireAdministrator\"@"; "(External project) Standalone Updater manifest should contain elevated rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12457.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12457.4dm new file mode 100755 index 0000000..4e662a8 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11090_TC12457.4dm @@ -0,0 +1,50 @@ +//%attributes = {} +// Check the default elevation right for the Updater (normal) +If (Is Windows) // Only on Windows + + var $build : cs.Build4D.Standalone + var $settings : Object + var $success : Boolean + var $manifestFile : 4D.File + var $manifestContent : Text + + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.sourceAppFolder:=Folder(Storage.settings.winVolumeDesktop) + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(Current project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"asInvoker\"@"; "(Current project) Standalone Updater manifest should contain normal rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + $manifestFile:=$build.settings.destinationFolder.file("Resources/Updater/Updater.exe.manifest") + ASSERT($manifestFile.exists; "(External project) Standalone Updater manifest should exist: "+$manifestFile.platformPath+$link) + + $manifestContent:=$manifestFile.getText() + ASSERT($manifestContent="@level=\"asInvoker\"@"; "(External project) Standalone Updater manifest should contain normal rights"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11092_TC11241.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11092_TC11241.4dm new file mode 100644 index 0000000..5525b4d --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11092_TC11241.4dm @@ -0,0 +1,22 @@ +//%attributes = {} +// The default value of "obfuscated" shall be "False" +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT((($build.settings.obfuscated#Null) && ($build.settings.obfuscated=False)); "Standalone: obfuscated default setting shall be false"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11094_TC11250.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11094_TC11250.4dm new file mode 100644 index 0000000..83f7481 --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11094_TC11250.4dm @@ -0,0 +1,30 @@ +//%attributes = {} +// The default value of "packedProject" shall be "True" +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=Folder(Storage.settings.winVolumeDesktop) +$settings.excludeModules:=New collection("mecab") + + +logGitHubActions(Current method name) + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + +$build:=cs.Build4D.Standalone.new($settings) + +ASSERT((($build.settings.packedProject#Null) && ($build.settings.packedProject)); "Standalone: obfuscated default setting shall be false"+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11095_TC11481.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11095_TC11481.4dm new file mode 100644 index 0000000..1d7237c --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11095_TC11481.4dm @@ -0,0 +1,45 @@ +//%attributes = {} +// Remove a file located at a relative path +var $build : cs.Build4D.Standalone +var $settings : Object +var $success : Boolean +var $modulePath : 4D.Folder +var $link : Text +$link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + +logGitHubActions(Current method name) + +// MARK:- Current project + +$settings:=New object() +$settings.formulaForLogs:=Formula(logGitHubActions($1)) +$settings.destinationFolder:="./Test/" +$settings.license:=Storage.settings.licenseUUD +$settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) +$settings.excludeModules:=New collection("mecab") + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(Current project) Standalone build should success"+$link) + +$modulePath:=$build._structureFolder.parent.folder("Resources/mecab/") +ASSERT($modulePath.exists=False; "(Current project) Module folder shouldn't exist: "+$modulePath.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) + +// MARK:- External project + +$settings.projectFile:=Storage.settings.externalProjectFile + +$build:=cs.Build4D.Standalone.new($settings) +$success:=$build.build() + +ASSERT($success; "(External project) Standalone build should success"+$link) + +$modulePath:=$build._structureFolder.parent.folder("Resources/mecab/") +ASSERT($modulePath.exists=False; "(Current project) Module folder shouldn't exist: "+$modulePath.platformPath+$link) + +// Cleanup build folder +Folder("/PACKAGE/Test").delete(fk recursive) diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11483.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11483.4dm new file mode 100644 index 0000000..a56a39a --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11483.4dm @@ -0,0 +1,46 @@ +//%attributes = {} +// Use SDI mode on Windows +If (Is Windows) + var $build : cs.Build4D.Standalone + var $settings; $info : Object + var $success : Boolean + var $link : Text + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + $settings.useSDI:=True + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(Current project) Standalone build should success"+$link) + + $info:=$build.settings.destinationFolder.file("Resources/Info.plist").getAppInfo() + ASSERT($info.SDIRuntime="1"; "(Current project) Standalone SDI mode should be true"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(External project) Standalone build should success"+$link) + + $info:=$build.settings.destinationFolder.file("Resources/Info.plist").getAppInfo() + ASSERT($info.SDIRuntime="1"; "(Current project) Standalone SDI mode should be true"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11485.4dm b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11485.4dm new file mode 100755 index 0000000..324b23a --- /dev/null +++ b/Build4D_UnitTests/Project/Sources/Methods/ut_3_R11097_TC11485.4dm @@ -0,0 +1,46 @@ +//%attributes = {} +// Use MDI mode on Windows +If (Is Windows) + var $build : cs.Build4D.Standalone + var $settings; $info : Object + var $success : Boolean + var $link : Text + $link:=" (https://dev.azure.com/4dimension/4D/_workitems/edit/"+Substring(Current method name; Position("_TC"; Current method name)+3)+")" + + logGitHubActions(Current method name) + + // MARK:- Current project + + $settings:=New object() + $settings.formulaForLogs:=Formula(logGitHubActions($1)) + $settings.destinationFolder:="./Test/" + $settings.license:=Storage.settings.licenseUUD + $settings.sourceAppFolder:=(Is macOS) ? Folder(Storage.settings.macVolumeDesktop) : Folder(Storage.settings.winVolumeDesktop) + $settings.useSDI:=False + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(Current project) Standalone build should success"+$link) + + $info:=$build.settings.destinationFolder.file("Resources/Info.plist").getAppInfo() + ASSERT($info.SDIRuntime="0"; "(Current project) Standalone SDI mode should be true"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) + + // MARK:- External project + + $settings.projectFile:=Storage.settings.externalProjectFile + + $build:=cs.Build4D.Standalone.new($settings) + $success:=$build.build() + + ASSERT($success; "(External project) Standalone build should success"+$link) + + $info:=$build.settings.destinationFolder.file("Resources/Info.plist").getAppInfo() + ASSERT($info.SDIRuntime="0"; "(Current project) Standalone SDI mode should be true"+$link) + + // Cleanup build folder + Folder("/PACKAGE/Test").delete(fk recursive) +End if diff --git a/Build4D_UnitTests/Project/Sources/folders.json b/Build4D_UnitTests/Project/Sources/folders.json index 7a5049e..286eb9b 100644 --- a/Build4D_UnitTests/Project/Sources/folders.json +++ b/Build4D_UnitTests/Project/Sources/folders.json @@ -85,10 +85,9 @@ }, "3_R11079": { "methods": [ - "mut_3_R11079_TC11171" + "ut_3_R11079_TC11171" ] }, - "3_R11080": {}, "3_R11081": { "methods": [ "ut_3_R11081_TC" @@ -106,6 +105,61 @@ "ut_3_R11084_TC11200" ] }, + "3_R11085": { + "methods": [ + "ut_3_R11085_TC11204", + "ut_3_R11085_TC11206" + ] + }, + "3_R11086": { + "methods": [ + "mut_3_R11086_TC11488" + ] + }, + "3_R11087": { + "methods": [ + "mut_3_R11087_TC11217", + "ut_3_R11087_TC11207" + ] + }, + "3_R11088": { + "methods": [ + "ut_3_R11088_TC11220" + ] + }, + "3_R11089": { + "methods": [ + "ut_3_R11089_TC11233" + ] + }, + "3_R11090": { + "methods": [ + "ut_3_R11090_TC12455", + "ut_3_R11090_TC12456", + "ut_3_R11090_TC12457" + ] + }, + "3_R11092": { + "methods": [ + "ut_3_R11092_TC11241" + ] + }, + "3_R11094": { + "methods": [ + "ut_3_R11094_TC11250" + ] + }, + "3_R11095": { + "methods": [ + "ut_3_R11095_TC11481" + ] + }, + "3_R11097": { + "methods": [ + "ut_3_R11097_TC11483", + "ut_3_R11097_TC11485" + ] + }, "CompiledProject": { "groups": [ "1_R3485", @@ -133,14 +187,22 @@ "3_R11077", "3_R11078", "3_R11079", - "3_R11080", "3_R11081", "3_R11083", - "3_R11084" + "3_R11084", + "3_R11085", + "3_R11086", + "3_R11087", + "3_R11088", + "3_R11089", + "3_R11090", + "3_R11092", + "3_R11094", + "3_R11095", + "3_R11097" ], "methods": [ - "runUnitTests3", - "zzzStandalone" + "runUnitTests3" ] }, "trash": {} diff --git a/Build4D_UnitTests/Resources/UnitTests.txt b/Build4D_UnitTests/Resources/UnitTests.txt index e69de29..4f2ff29 100644 --- a/Build4D_UnitTests/Resources/UnitTests.txt +++ b/Build4D_UnitTests/Resources/UnitTests.txt @@ -0,0 +1 @@ +DO NOT REMOVE: MANDATORY FOR UNIT TESTS \ No newline at end of file diff --git a/Build4D_UnitTests/Settings/UT_Settings.json b/Build4D_UnitTests/Settings/UT_Settings.json index d7bf617..4cad522 100644 --- a/Build4D_UnitTests/Settings/UT_Settings.json +++ b/Build4D_UnitTests/Settings/UT_Settings.json @@ -1,5 +1,9 @@ { "licenseUUD":"/PACKAGE/Settings/4UUD.license4D", - "macVolumeDesktop":"/Applications/4D v0.0/4D Volume Desktop.app/", - "winVolumeDesktop":"C:/Program Files/4D/4D v0.0/4D Volume Desktop/" + "invalid_LicenseUUD":"/PACKAGE/Settings/invalid_4UUD.license4D", + "macVolumeDesktop":"/Applications/4D v20.0/4D Volume Desktop.app/", + "winVolumeDesktop":"C:/Program Files/4D/4D v20.0/4D Volume Desktop/", + "invalid_macVolumeDesktop":"/Applications/4D v0.0/4D Volume Desktop.app/", + "invalid_winVolumeDesktop":"C:/Program Files/4D/4D v0.0/4D Volume Desktop/", + "macCertificate":"Damien FUZEAU" } \ No newline at end of file From c14c2be78339f3e47b033baa0c3e77e8c94a4b0e Mon Sep 17 00:00:00 2001 From: Damien Fuzeau Date: Wed, 28 Jun 2023 11:33:22 +0200 Subject: [PATCH 21/29] User manual for Build4D_UnitTests in the README file --- Build4D_UnitTests/README.md | 65 ++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/Build4D_UnitTests/README.md b/Build4D_UnitTests/README.md index ee725c8..eac998b 100644 --- a/Build4D_UnitTests/README.md +++ b/Build4D_UnitTests/README.md @@ -1 +1,64 @@ -## Build4D_UnitTests: DO NOT REMOVE FOR UNIT TESTS \ No newline at end of file +Build4D_UnitTests User Manual += +>To test the latest version of Build4D, open the Build4D project and run the buildComponent method. This will build the component directly in the Build4D_UnitTests project. + +User settings +- +User settings are mandatory to perform the unit tests on your computer. They are stored in the **Settings/UT_Settings.json** file. +| Attribut | Description | +| :- | :- | +| macCertificate | Certificate name for macOS signature | +| licenseUUD | POSIX path to a **valid** UUD licence file | +| invalid_LicenseUUD | POSIX path to an **invalid** licence file (not a UUD file) | +| macVolumeDesktop | POSIX path to the macOS Volume Desktop folder | +| winVolumeDesktop | POSIX path to the Windows Volume Desktop folder | +| invalid_macVolumeDesktop | POSIX path to a macOS Volume Desktop folder with different version from running 4D version | +| invalid_winVolumeDesktop | POSIX path to a Windows Volume Desktop folder with different version from running 4D version | + +Nomenclature +- +Unit tests methods are formatted this way: **{m}ut_{scope}_R{requirement id}_TC{test case id}**. + +Each automatic unit test method is prefixed with **ut_**. + +Each manual unit test method is prefixed **mut_**. These tests needs human actions such as certificate password for macOS signature or icon checking. + +The scopes are: +| Scope | Description | +| :- | :- | +| 1 | Compiled project | +| 2 | Component | +| 3 | Standalone application | +| 4 | Client application | +| 5 | Server application | + +Run Unit Tests +- +Manual unit tests can be performed by running the **runManualUnitTests** method. + +Automatic unit tests can be performed by running the **runAutomaticUnitTests** method. + +Automatic unit tests for a specified scope can be performed by running the **runUnitTests1{scope}** method. + +Each unit test is performed related to the current project and, if it's relevant, related to an external project. + +Run Unit Tests in CLI +- +Running all automatic unit tests can be performed from CLI using the parameter: +**--user-param "test"**. + +Reports +- +When starting a test method, the timestamp is stored in the **UT_start.log** file, in the project package. + +When ending a test method, the timestamp is stored in the **UT_end.log** file, in the project package. + +When running a unit test method, the unit test method name and the timestamp is stored in the **UT_run.log** file, in the project package. Code errors are also logged in this file. + +When a false assertion is encountered in a unit test method, the assertion details is stored in the **UT_errors.log** file, in the project package. At the end, if this file does not exist, unit tests passed. + +Note that **.log** files can be opened in the console during tests execution to check the content evolution. + +Miscellaneous +- +The **logGitHubActions** formats messages in GitHub Actions fomat so that they can be viewed in live in its console. From 44895b3ca47f1c2e172f288e3c8e98d0a4b53995 Mon Sep 17 00:00:00 2001 From: Vanessa Talbot <35832071+vanessa-talbot@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:31:19 +0200 Subject: [PATCH 22/29] Add example with dependent component --- Build4D/Documentation/Classes/Standalone.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index fd2c0dc..9700cd6 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -93,10 +93,16 @@ $settings.useSDI:=False $settings.startElevated:=False $settings.lastDataPathLookup:="ByAppPath" +// Specify the components required for compilation +$componentsFolder:=Folder(fk documents folder).folder("4D v20.0/4D.app/Contents/Components") +$components:=New collection() +$components.push($componentsFolder.file("4D WritePro Interface.4dbase/4D WritePro Interface.4DZ")) +$settings.compilerOptions:=New object("components"; $components) + // Define 4D Volume Desktop path $settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app") -// Delete unneccessary module +// Delete unnecessary module $settings.excludeModules:=New collection("CEF"; "MeCab") // Include folders and files From 389ab386d1c3f1be2df2a5347a23de12c6e28b17 Mon Sep 17 00:00:00 2001 From: mouna-elmaazouzi <118451160+mouna-elmaazouzi@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:15:51 +0100 Subject: [PATCH 23/29] English check for _core.md --- Build4D/Documentation/Classes/_core.md | 50 +++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Build4D/Documentation/Classes/_core.md b/Build4D/Documentation/Classes/_core.md index 18ac3d2..8c9251d 100644 --- a/Build4D/Documentation/Classes/_core.md +++ b/Build4D/Documentation/Classes/_core.md @@ -1,7 +1,7 @@ ## Description -This class is a base class used by the other classes to create a compiled project or a component. It is composed of: +This class is a base class used by the other classes to create a compiled project or a component. It is composed of the following: * [Class constructor](#class-constructor) * [Function \_checkDestinationFolder](#function-checkDestinationFolder) @@ -26,8 +26,8 @@ Class constructor($target : Text; $customSettings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $target | Text | in | The target to build. The possible values are "CompiledProject" or "Component". | -| $customSettings | Object | in | Object containing all settings for target build | +| $target | Text | in | The target to build, the possible values are "CompiledProject" or "Component". | +| $customSettings | Object | in | Object containing all settings for target build. | $customSettings is an object that contains the following parameters: @@ -39,7 +39,7 @@ $customSettings is an object that contains the following parameters: |\_isCurrentProject | Boolean | True if the project is the current one.| |\_isDefaultDestinationFolder | Boolean | True if the destination folder is the one computed automatically.| |\_structureFolder | Folder | Folder of the destination structure.| -|settings | Object | Root object containing all settings for target build. Can be overriden by a constructor's parameter. The structure of the $settings object is described in each class corresponding to the target.| +|settings | Object | Root object containing all settings for target build. It can be overriden by a constructor's parameter. The structure of the $settings object is described in each class corresponding to the target.|

Function _checkDestinationFolder

@@ -59,9 +59,9 @@ Function _compileProject() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the compilation has succeeded. If not, the compilation's result object is included in an error log. | +| $status | Boolean | out | True if the compilation has succeeded. Otherwise, the compilation's result object is included in an error log. | -Compiles the project, with the settings.compilerOptions if exists. +Compiles the project with the settings.compilerOptions (if it exists).

Function _copySourceApp

@@ -73,7 +73,7 @@ Function _copySourceApp() -> $status : Boolean |---|---|---|---| | $status | Boolean | out | True if the copy is successful. | -Copy the source application (4D Volume Desktop or 4D Server) in the destination folder. +Copies the source application (4D Volume Desktop or 4D Server) in the destination folder.

Function _create4DZ

@@ -82,9 +82,9 @@ Function _create4DZ() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the compression has succeeded. If not, the archive creation result object is included in an error log. | +| $status | Boolean | out | True if the compression has succeeded. Otherwise, the archive creation's result object is included in an error log. | -Creates the 4DZ file of the project, and deletes the Project folder if successful. +Creates the 4DZ file of the project, and deletes the Project folder if successful.

Function _createStructure

@@ -104,8 +104,8 @@ Function _deletePaths($paths : Collection) -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $paths | Collection of texts | in | List of folders and files to delete | -| $status | Boolean | out | True if all paths have been correctly removed. If not, an error log is created with "path" information. | +| $paths | Collection of texts | in | List of folders and files to delete. | +| $status | Boolean | out | True if all paths have been correctly removed. Otherwise, an error log is created with "path" information. | Deletes folders and files from the destination structure. @@ -116,9 +116,9 @@ Function _excludeModules() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if all modules have been correctly removed. If not, an error log is created with "path" information.| +| $status | Boolean | out | True if all modules have been correctly removed. Otherwise, an error log is created with "path" information.| -Deletes the folders and files composing the module to be removed according to the information in the "/RESOURCES/BuildappOptionalModules.json" file +Deletes the folders and files composing the module to be removed according to the information in the "/RESOURCES/BuildappOptionalModules.json" file.

Function _generateLicense

@@ -127,9 +127,9 @@ Function _generateLicense() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the deployment license have been correctly created. If not, xxx.| +| $status | Boolean | out | True if the deployment license have been correctly created. Otherwise, xxx.| -Create the deployment license file in the license folder of the generated application. +Creates the deployment license file in the license folder of the generated application.

Function _includePaths

@@ -138,8 +138,8 @@ Function _includePaths($pathsObj : Collection) -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $paths | Collection of objects | in | List of folder and file objects to include | -| $status | Boolean | out | True if all paths have been correctly copied. If not, an error log is created with "sourcePath" and "destinationPath" information. | +| $paths | Collection of objects | in | List of folder and file objects to include. | +| $status | Boolean | out | True if all paths have been correctly copied. Otherwise, an error log is created with "sourcePath" and "destinationPath" information. | Includes folders and files into the destination structure. @@ -150,9 +150,9 @@ Function _log($log : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $log | Object | in | $log contains attributes "function", "message", "messageSeverity" and optionnaly "result", "path", "sourcePath", "destinationPath". | +| $log | Object | in | Object containing the attributes: "function", "message", "messageSeverity", and optionnaly: "result", "path", "sourcePath", "destinationPath". | -Calls the settings.formulaForLogs formula with $log object parameter. +Calls the settings.formulaForLogs formula with the $log object parameter.

Function _overrideSettings

@@ -161,7 +161,7 @@ Function _overrideSettings($settings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $settings | Object | in | Settings passed by the derived class to override the default settings | +| $settings | Object | in | Settings passed by the derived class to override the default settings. | Overrides the default target settings with the $settings parameter. @@ -172,11 +172,11 @@ Function _resolvePath($path : Text; $baseFolder : 4D.Folder) -> $object : Object ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $path | Text | in | Relative path to $baseFolder | -| $baseFolder | 4D.Folder | in | Absolute path | -| $object | 4D.Folder or 4D.File | out | Return a 4D folder or 4D File | +| $path | Text | in | Relative path to $baseFolder. | +| $baseFolder | 4D.Folder | in | Absolute path. | +| $object | 4D.Folder or 4D.File | out | 4D folder or 4D File. | -Resolves a relative/absolute/filesystem string path to Folder/File object. +Resolves a relative/absolute/filesystem string path to a Folder/File object.

Function _setAppOptions

@@ -187,7 +187,7 @@ Function _setAppOptions()-> $status : Boolean |---|---|---|---| | $status | Boolean | out | True if the information has been correctly added. | -Set information to the application. +Sets the information to the application.

Function _sign

From 626b9cf66f1c1195ff565a009e2977c23f797146 Mon Sep 17 00:00:00 2001 From: mouna-elmaazouzi <118451160+mouna-elmaazouzi@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:38:13 +0100 Subject: [PATCH 24/29] English check for Standalone.md --- Build4D/Documentation/Classes/Standalone.md | 54 ++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index 9700cd6..db59a49 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -1,7 +1,7 @@ ## Description -This class allows you to create a standalone application. It is composed of: +This class allows you to create a standalone application. It is composed of the following: * a [Class constructor](#class-constructor) * a [\_renameExecutable](#renameExecutable) function @@ -14,40 +14,40 @@ Class constructor($customSettings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in "/RESOURCES/Standalone.json" file | +| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in the "/RESOURCES/Standalone.json" file. | $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| -|buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| -|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| +|buildName | String | Name of the target build, defined by the component if missing in the custom settings.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project (not necessary if building the current project).| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem), defined by the component if missing in the custom settings.| |sourceAppFolder| Folder or String | Folder of the 4D Volume Desktop (relative to the open project/absolute/filesystem).| -|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if it is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| -|obfuscated | Boolean | True if the 4DZ shall not be dezippable.| -|lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName" (Default value), "ByAppPath"| +|obfuscated | Boolean | True if the 4DZ is to not be dezippable.| +|lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName" (Default value) and "ByAppPath".| |useSDI| Boolean | On Windows, use the SDI interface mode instead of the MDI.| |startElevated| Boolean | On Windows, allow to start the Updater with elevated privileges.| |iconPath| File or String | File path of the icon to be used instead of the 4D Volume Desktop icon.| -|versioning| Object | Object contains the contents of the application information.| -|versioning.version| String | Version number | -|versioning.copyright| String | Copyright text | -|versioning.companyName| String | Company name| -|versioning.fileDescription| String | Description (Windows only)| -|versioning.internalName| String | Internal name (Windows only)| +|versioning| Object | Object containing the contents of the application information.| +|versioning.version| String | Version number. | +|versioning.copyright| String | Copyright text. | +|versioning.companyName| String | Company name. | +|versioning.fileDescription| String | Description (Windows only).| +|versioning.internalName| String | Internal name (Windows only).| |includePaths[] | Collection of Objects | Collection of folders and files to include.| |includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem).| |includePaths[].destination | Folder, File, or String | Destination folder path (relative to the built project/absolute/filesystem).| |deletePaths[] | Collection of Folder, File, or Strings | Collection of paths to folders and files to be deleted (relative to the built project/absolute/filesystem strings).| -|excludeModules| Collection of Strings | Collection of module names to exclude from final application. The module names can be found in the "BuildappOptionalModules.json" file in the resources of 4D application.| +|excludeModules| Collection of Strings | Collection of module names to exclude from final application. The module names can be found in the "BuildappOptionalModules.json" file in the resources of the 4D application.| |license| File or String | Unlimited desktop license file (relative to the built project/absolute/filesystem).| |signApplication.macSignature | Boolean | Signs the built applications.| -|signApplication.macCertificate | String | Certificate name used for signature.| +|signApplication.macCertificate | String | Certificate name used for signature.| |signApplication.adHocSignature | Boolean | Signs the built applications with AdHoc signature if macSignature not performed.| |logger | Formula | Formula called when a log is written.| - +

_renameExecutable

```4D @@ -55,9 +55,9 @@ Function _renameExecutable() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the executable has correctly renamed. | +| $status | Boolean | out | True if the executable has been correctly renamed. | -Rename the executable. +Renames the executable. ### build() @@ -66,9 +66,9 @@ Function build() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the standalone has been correctly executed| +| $status | Boolean | out | True if the standalone has been correctly executed.| -Build the standalone application. +Builds the standalone application. ## Example @@ -81,7 +81,7 @@ var $success : Boolean $settings:=New object() -// Define external project file +// Define the external project file $settings.projectFile:=Folder(fk documents folder).file("Contact/Project/Contact.4DProject") // Configure the application @@ -99,17 +99,17 @@ $components:=New collection() $components.push($componentsFolder.file("4D WritePro Interface.4dbase/4D WritePro Interface.4DZ")) $settings.compilerOptions:=New object("components"; $components) -// Define 4D Volume Desktop path +// Define the 4D Volume Desktop path $settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app") -// Delete unnecessary module +// Delete the unnecessary module $settings.excludeModules:=New collection("CEF"; "MeCab") -// Include folders and files +// Include the folders and files $settings.includePaths:=New collection $settings.includePaths.push(New object("source"; "Documentation/")) -// Delete folders and files +// Delete the folders and files $settings.deletePaths:=New collection $settings.deletePaths.push("Resources/Dev/") @@ -130,7 +130,7 @@ $settings.signApplication:=New object $settings.signApplication.macSignature:=True $settings.signApplication.macCertificate:="xxxxxx" -// Launch build +// Launch the build $build:=cs.Build4D.Standalone.new($settings) $success:=$build.build() ``` From d449a8e20365f48094878a10b83193063fabd787 Mon Sep 17 00:00:00 2001 From: mouna-elmaazouzi <118451160+mouna-elmaazouzi@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:26:33 +0100 Subject: [PATCH 25/29] Update English check for Standalone.md --- Build4D/Documentation/Classes/Standalone.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index db59a49..6b2f7f5 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -28,8 +28,8 @@ $customSettings is an object that contains the following parameters: |packedProject | Boolean | True if the project is compressed into a 4DZ file.| |obfuscated | Boolean | True if the 4DZ is to not be dezippable.| |lastDataPathLookup| String | Defines the way the application stores its link with the last data file. Possible values: "ByAppName" (Default value) and "ByAppPath".| -|useSDI| Boolean | On Windows, use the SDI interface mode instead of the MDI.| -|startElevated| Boolean | On Windows, allow to start the Updater with elevated privileges.| +|useSDI| Boolean | Allows to use the SDI interface mode instead of the MDI (Windows only).| +|startElevated| Boolean | Allows to start the Updater with elevated privileges (Windows only).| |iconPath| File or String | File path of the icon to be used instead of the 4D Volume Desktop icon.| |versioning| Object | Object containing the contents of the application information.| |versioning.version| String | Version number. | From 839526b137232c1386f6fa501f21a2a15ea2f50e Mon Sep 17 00:00:00 2001 From: mouna-elmaazouzi <118451160+mouna-elmaazouzi@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:34:36 +0100 Subject: [PATCH 26/29] English check update CompiledProject.md --- Build4D/Documentation/Classes/CompiledProject.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Build4D/Documentation/Classes/CompiledProject.md b/Build4D/Documentation/Classes/CompiledProject.md index fc7dcd7..a78c643 100644 --- a/Build4D/Documentation/Classes/CompiledProject.md +++ b/Build4D/Documentation/Classes/CompiledProject.md @@ -1,7 +1,7 @@ ## Description -This class allows you to create a compiled project. It is composed of: +This class allows you to create a compiled project. It is composed of the following: * a [Class constructor](#class-constructor) * a [build()](#build) function @@ -13,18 +13,18 @@ Class constructor($customSettings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in "/RESOURCES/CompiledProject.json" file | +| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in the "/RESOURCES/CompiledProject.json" file. | $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| -|buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| -|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| -|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| +|buildName | String | Name of the target build, defined by the component if missing in the custom settings.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project (not necessary if building the current project).| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem), defined by the component if missing in the custom settings.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if it is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| -|obfuscated | Boolean | True if the 4DZ shall not be dezippable.| +|obfuscated | Boolean | True if the 4DZ is to not be dezippable.| |includePaths[] | Collection of Objects | Collection of folders and files to include.| |includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem strings).| |includePaths[].destination | Folder, File, or String | Destination folder path (relative to the built project/absolute/filesystem).| @@ -38,7 +38,7 @@ Function build() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the build has been correctly executed | +| $status | Boolean | out | True if the build has been correctly executed. | Builds the compiled project. From 397b370b6f9b4f57ea5468af89cf59a8dc4719e9 Mon Sep 17 00:00:00 2001 From: mouna-elmaazouzi <118451160+mouna-elmaazouzi@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:38:05 +0100 Subject: [PATCH 27/29] English check update Component.md --- Build4D/Documentation/Classes/Component.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Build4D/Documentation/Classes/Component.md b/Build4D/Documentation/Classes/Component.md index 07612c1..fc7390d 100644 --- a/Build4D/Documentation/Classes/Component.md +++ b/Build4D/Documentation/Classes/Component.md @@ -1,7 +1,7 @@ ## Description -This class allows you to create a component. It is composed of: +This class allows you to create a component. It is composed of the following: * a [Class constructor](#class-constructor) * a [build()](#build) function @@ -13,18 +13,18 @@ Class constructor($customSettings : Object) ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in "/RESOURCES/Component.json" file | +| $customSettings | Object | in | $customSettings is a custom settings object overriding target default settings stored in the "/RESOURCES/Component.json" file. | $customSettings is an object that contains the following parameters: | Attributes | Type | Description | |---|---|---| -|buildName | String | Name of the target build. Defined by the component if missing in the custom settings.| -|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project. Not necessary if building the current project.| -|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem). Defined by the component if missing in the custom settings.| -|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if is not null. For more details about the object format, read the documentation of the Compile project command.| +|buildName | String | Name of the target build, defined by the component if missing in the custom settings.| +|projectFile | File or String | Project file (relative to the open project/absolute/filesystem). Pass the project file path if you want to build an external project (not necessary if building the current project=.| +|destinationFolder | Folder or String | Folder where the build will be generated (relative to the open project/absolute/filesystem), defined by the component if missing in the custom settings.| +|compilerOptions | Object | Compile options. The object is passed as parameter to the "Compile project" command if it is not null. For more details about the object format, read the documentation of the Compile project command.| |packedProject | Boolean | True if the project is compressed into a 4DZ file.| -|obfuscated | Boolean | True if the 4DZ shall not be dezippable.| +|obfuscated | Boolean | True if the 4DZ is to not be dezippable.| |includePaths[] | Collection of Objects | Collection of folders and files to include.| |includePaths[].source | Folder, File, or String | Source folder or file path (relative to the open project/absolute/filesystem).| |includePaths[].destination | Folder, File, or String | Destination folder or file path (relative to the built project/absolute/filesystem).| @@ -41,7 +41,7 @@ Function build() -> $status : Boolean ``` | Parameter | Type | in/out | Description | |---|---|---|---| -| $status | Boolean | out | True if the build has been correctly executed| +| $status | Boolean | out | True if the build has been correctly executed.| Build the component. From ff76dcf4c14898666632dfab6d522a599c4a7698 Mon Sep 17 00:00:00 2001 From: Vanessa Talbot <35832071+vanessa-talbot@users.noreply.github.com> Date: Thu, 6 Jul 2023 10:25:15 +0200 Subject: [PATCH 28/29] Add dependency component --- Build4D/Documentation/Classes/Standalone.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index 6b2f7f5..4c96a86 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -88,7 +88,7 @@ $settings.projectFile:=Folder(fk documents folder).file("Contact/Project/Contact $settings.buildName:="myApp" $settings.destinationFolder:="Test/" $settings.obfuscated:=True -$settings.packedProject:=False +$settings.packedProject:=True $settings.useSDI:=False $settings.startElevated:=False $settings.lastDataPathLookup:="ByAppPath" @@ -108,6 +108,9 @@ $settings.excludeModules:=New collection("CEF"; "MeCab") // Include the folders and files $settings.includePaths:=New collection $settings.includePaths.push(New object("source"; "Documentation/")) +$settings.includePaths.push(New object("source"; $componentsFolder.folder("4D WritePro Interface.4dbase").path; "destination"; "../Components/")) +$settings.includePaths.push(New object("source"; $componentsFolder.folder("4D SVG.4dbase").path; "destination"; "../Components/")) + // Delete the folders and files $settings.deletePaths:=New collection From 946ac424c83c46d05c95be27bd056272eacd982b Mon Sep 17 00:00:00 2001 From: Vanessa Talbot <35832071+vanessa-talbot@users.noreply.github.com> Date: Thu, 6 Jul 2023 14:25:46 +0200 Subject: [PATCH 29/29] Update example with object literal syntax --- Build4D/Documentation/Classes/Standalone.md | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Build4D/Documentation/Classes/Standalone.md b/Build4D/Documentation/Classes/Standalone.md index 4c96a86..c7281c3 100644 --- a/Build4D/Documentation/Classes/Standalone.md +++ b/Build4D/Documentation/Classes/Standalone.md @@ -79,7 +79,7 @@ var $build : cs.Build4D.Standalone var $settings : Object var $success : Boolean -$settings:=New object() +$settings:={} // Define the external project file $settings.projectFile:=Folder(fk documents folder).file("Contact/Project/Contact.4DProject") @@ -95,32 +95,30 @@ $settings.lastDataPathLookup:="ByAppPath" // Specify the components required for compilation $componentsFolder:=Folder(fk documents folder).folder("4D v20.0/4D.app/Contents/Components") -$components:=New collection() +$components:=[] $components.push($componentsFolder.file("4D WritePro Interface.4dbase/4D WritePro Interface.4DZ")) -$settings.compilerOptions:=New object("components"; $components) +$settings.compilerOptions:={components: $components} // Define the 4D Volume Desktop path $settings.sourceAppFolder:=Folder(fk documents folder).folder("4D v20.0/4D Volume Desktop.app") // Delete the unnecessary module -$settings.excludeModules:=New collection("CEF"; "MeCab") +$settings.excludeModules:=["CEF"; "MeCab"] // Include the folders and files -$settings.includePaths:=New collection -$settings.includePaths.push(New object("source"; "Documentation/")) -$settings.includePaths.push(New object("source"; $componentsFolder.folder("4D WritePro Interface.4dbase").path; "destination"; "../Components/")) -$settings.includePaths.push(New object("source"; $componentsFolder.folder("4D SVG.4dbase").path; "destination"; "../Components/")) - +$settings.includePaths:=[] +$settings.includePaths.push({source: $componentsFolder.folder("4D WritePro Interface.4dbase").path; destination: "../Components/"}) +$settings.includePaths.push({source: $componentsFolder.folder("4D SVG.4dbase").path; destination: "../Components/"}) // Delete the folders and files -$settings.deletePaths:=New collection +$settings.deletePaths:=[] $settings.deletePaths.push("Resources/Dev/") // Add the application icon $settings.iconPath:="/RESOURCES/myIcon.icns" // Add the application information -$settings.versioning:=New object +$settings.versioning:={} $settings.versioning.version:="version" $settings.versioning.copyright:="copyright" $settings.versioning.companyName:="companyName" @@ -129,7 +127,7 @@ $settings.versioning.companyName:="companyName" $settings.license:=Folder(fk licenses folder).file("XXXXX.license4D") // Sign the macOS appplication -$settings.signApplication:=New object +$settings.signApplication:={} $settings.signApplication.macSignature:=True $settings.signApplication.macCertificate:="xxxxxx"