Skip to content

Commit

Permalink
Merge pull request #678 from intersystems/v0.9.x-fix-lang-ext-upgrade
Browse files Browse the repository at this point in the history
fix: preserve user-side changes to lang. ext. outside of comment tags
  • Loading branch information
isc-tleavitt authored Jan 6, 2025
2 parents e780e02 + 6bea241 commit 983bf03
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 8 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased - 0.9.2+snapshot]

### Added
- #682 When downloading IPM via the `enable` command from a remote registry, allow user to pass in the registry name (or get the only existent one), instead of the deployment enabled registry.

### Fixed
- #682 When enabling IPM in a namespace using local IPM caches, check for existence of `<iris-root>/lib/ipm/` beforing querying it.
- #682 Use more standard wording of mapping when enabling IPM
- #681 Convert specified namespaces to upper case for `enable` and `unmap` commands.
- #680 Always export static files (README.md, LICENSE, requirements.txt) if existent
- #678 Only update comment-flagged part of the language extension, allowing users to keep their custom code when upgrading
- #680, #683 Always export static files (README.md, LICENSE, requirements.txt, CHANGELOG.md) if existent

### Changed
- #682 When downloading IPM via the `enable` command from a remote registry, allow user to pass in the registry name (or get the only existent one), instead of the deployment enabled registry.

## [0.9.1] - 2024-12-18

### Added
Expand Down
10 changes: 5 additions & 5 deletions src/cls/IPM/Main.cls
Original file line number Diff line number Diff line change
Expand Up @@ -2720,7 +2720,6 @@ ClassMethod UpdateLanguageExtensionsOne(RoutineName As %String, pTestOnly As %Bo
{
Set tRtn = ##class(%Routine).%New(RoutineName)
If ##class(%Routine).Exists(RoutineName) {
Set tEnded = 1
While 'tRtn.AtEnd {
Set tLine = tRtn.ReadLine()
If $Match(tLine,$$$STARTTAGREGEX) {
Expand All @@ -2732,11 +2731,12 @@ ClassMethod UpdateLanguageExtensionsOne(RoutineName As %String, pTestOnly As %Bo
For i=1:1:tGenLines {
Set tRtnLines($Increment(tRtnLines)) = tGenLines(i)
}
}
} Else {
// outside of the tags, just copy the lines to preserve users' custom code
Set tRtnLines($Increment(tRtnLines)) = tLine
}
}
If 'tEnded {
Set tRtnLines($Increment(tRtnLines)) = $$$ENDTAGQ
} ElseIf 'pFound {
If 'pFound {
For i=1:1:tGenLines {
Set tRtnLines($Increment(tRtnLines)) = tGenLines(i)
}
Expand Down
171 changes: 171 additions & 0 deletions tests/unit_tests/Test/PM/Unit/LanguageExtension/Abstract.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
Include %IPM.Common

Class Test.PM.Unit.LanguageExtension.Abstract Extends %UnitTest.TestCase
{

/// Controls whether the test case will be run. Only the Abstract case should have this set to 1.
Parameter IsAbstractTestCase As Boolean = 1;

/// Name of the routine to be tested.
Parameter TestRoutine = "DummyRoutineForIPMTest.MAC";

/// Constant string to be used as custom code in the test cases.
Parameter CustomCode = " // This is some custom code";

/// Run by <B>RunTest</B> immediately before each test method in the test class is run.<br>
/// <dl>
/// <dt><i>testname</i>
/// <dd>Name of the test to be run. Required.
/// </dl>
Method OnBeforeOneTest(testname As %String) As %Status
{
If ##class(%Routine).Exists(..#TestRoutine) {
Quit ##class(%Routine).Delete(..#TestRoutine)
}
Quit $$$OK
}

/// Run by <B>RunTest</B> immediately after each test method in the test class is run.<br>
/// <dl>
/// <dt><i>testname</i>
/// <dd>Name of the test to be run. Required.
/// </dl>
Method OnAfterOneTest(testname As %String) As %Status
{
Quit ..OnBeforeOneTest(testname)
}

ClassMethod AppendLangExt1(ByRef content)
{
Set content($Increment(content)) = "ZPMDUMMYLANGUAGEEXTENSION(pArgs...)"
Set content($Increment(content)) = " Set x = 1"
}

ClassMethod AppendLangExt2(ByRef content)
{
Set content($Increment(content)) = "ZPMDUMMYLANGUAGEEXTENSION(pArgs...)"
Set content($Increment(content)) = " Set y = 2"
}

ClassMethod AppendLegacyStart(ByRef content)
{
Set content($Increment(content)) = $Replace($$$STARTTAGQ, "%IPM.Main", "%ZPM.PackageManager")
}

ClassMethod AppendLegacyEnd(ByRef content)
{
Set content($Increment(content)) = $Replace($$$ENDTAGQ, "%IPM.Main", "%ZPM.PackageManager")
}

ClassMethod AppendStart(ByRef content)
{
Set content($Increment(content)) = $$$STARTTAGQ
}

ClassMethod AppendEnd(ByRef content)
{
Set content($Increment(content)) = $$$ENDTAGQ
}

ClassMethod AppendContent(ByRef dest, ByRef src)
{
For i = 1:1:$Get(src) {
Set dest($Increment(dest)) = src(i)
}
}

/// Open TestRoutine, clear it, and write to it. The input should be a multi-dimensional array.
ClassMethod WriteToRoutine(ByRef input)
{
// Creating and saving an empty routine causes the routine to contain a whitespace, which causes tests to fail.
If '$Data(input) {
Quit
}
Set routine = ##class(%Routine).%New(..#TestRoutine)
Do routine.Clear()
For i = 1:1:$Get(input) {
Do routine.WriteLine(input(i))
}
$$$ThrowOnError(routine.Save())
}

/// Get the content of TestRoutine as a multi-dimensional array
ClassMethod ReadFromRoutine(Output output)
{
Kill output

If '##class(%Routine).Exists(..#TestRoutine) {
Quit
}
Set routine = ##class(%Routine).%New(..#TestRoutine)
While ('routine.AtEnd) {
Set output($Increment(output)) = routine.ReadLine()
}
}

ClassMethod CompareContents(ByRef content1, ByRef content2) As %Boolean
{
If $Data(content1) '= $Data(content2) {
Quit 0
}
If $Get(content1) '= $Get(content2) {
Quit 0
}
For i = 1:1:$Get(content1) {
If content1(i) '= content2(i) {
Return 0
}
}
Return 1
}

ClassMethod ContentToString(ByRef content, LineSep As %String = "\n") As %String
{
Set str = ""
For i = 1:1:$Get(content) {
Set str = str _ content(i) _ LineSep
}
Quit str
}

Method TestLanguageExtension()
{
If ..#IsAbstractTestCase {
Do $$$AssertSkipped($classname() _ "is an abstract test case")
Quit
}
// Get initial content and write to it
Do ..GetInitial(.initialContent)
Do ..WriteToRoutine(.initialContent)

// Update language extension
Do ..AppendStart(.routineContent)
Do ..AppendLangExt2(.routineContent)
Do ..AppendEnd(.routineContent)
Do ##class(%IPM.Main).UpdateLanguageExtensionsOne(..#TestRoutine, 0, .found, .routineContent)

// Get expected content, and expected found
Do ..GetExpected(.expectedContent, .expectedFound)

// Compare against routine content
Do ..ReadFromRoutine(.outputContent)
Do $$$AssertEquals((''found), (''expectedFound))
If '$$$AssertTrue(..CompareContents(.outputContent, .expectedContent)) {
Do $$$LogMessage("Output and expected content do not match !!!")
Do $$$LogMessage("Output : " _ ..ContentToString(.outputContent))
Do $$$LogMessage("Expected : " _ ..ContentToString(.expectedContent))
}
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
}

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
}

}
23 changes: 23 additions & 0 deletions tests/unit_tests/Test/PM/Unit/LanguageExtension/FreshInstall.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// Simulate a fresh install of the language extension, assuming the routine is nonexistent at the time of install.
Class Test.PM.Unit.LanguageExtension.FreshInstall Extends Test.PM.Unit.LanguageExtension.Abstract
{

Parameter IsAbstractTestCase As Boolean = 0;

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
Set found = 0

Do ..AppendStart(.content)
Do ..AppendLangExt2(.content)
Do ..AppendEnd(.content)
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// Simulate a fresh install of the language extension, assuming the routine contains only custom code at the time of install.
Class Test.PM.Unit.LanguageExtension.FreshInstallWithCustomCode Extends Test.PM.Unit.LanguageExtension.Abstract
{

Parameter IsAbstractTestCase As Boolean = 0;

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
Set found = 0

Set content($Increment(content)) = ..#CustomCode
Do ..AppendStart(.content)
Do ..AppendLangExt2(.content)
Do ..AppendEnd(.content)
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
Set content($Increment(content)) = ..#CustomCode
}

}
28 changes: 28 additions & 0 deletions tests/unit_tests/Test/PM/Unit/LanguageExtension/IllFormedTags.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// Ill-formed test case with only start tag but no end tag.
Class Test.PM.Unit.LanguageExtension.IllFormedTags Extends Test.PM.Unit.LanguageExtension.Abstract
{

Parameter IsAbstractTestCase As Boolean = 0;

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
Set found = 1

Set content($Increment(content)) = ..#CustomCode
Do ..AppendStart(.content)
Do ..AppendLangExt2(.content)
Do ..AppendEnd(.content)
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
Set content($Increment(content)) = ..#CustomCode
Do ..AppendStart(.content)
Do ..AppendLangExt1(.content)
Set content($Increment(content)) = ..#CustomCode
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/// Simulate upgrading from an older version of the language extension, assuming the routine contains only the older language extension.
Class Test.PM.Unit.LanguageExtension.UpgradeFromLegacy Extends Test.PM.Unit.LanguageExtension.Abstract
{

Parameter IsAbstractTestCase As Boolean = 0;

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
Set found = 1

Do ..AppendStart(.content)
Do ..AppendLangExt2(.content)
Do ..AppendEnd(.content)
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
Do ..AppendStart(.content)
Do ..AppendLangExt1(.content)
Do ..AppendEnd(.content)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Simulate upgrading from an older version of the language extension, assuming the routine contains both the older language extension and some custom code.
Class Test.PM.Unit.LanguageExtension.UpgradeFromLegacyWithCustomCode Extends Test.PM.Unit.LanguageExtension.Abstract
{

Parameter IsAbstractTestCase As Boolean = 0;

/// Construct the expected content of the routine after the language extension is updated.
/// Also construct the expected "found" value indicating if an older language extension was found.
ClassMethod GetExpected(Output content, Output found)
{
Set found = 1

Set content($Increment(content)) = ..#CustomCode
Do ..AppendStart(.content)
Do ..AppendLangExt2(.content)
Do ..AppendEnd(.content)
Set content($Increment(content)) = ..#CustomCode
}

/// Construct the initial content of the routine. Could be empty.
ClassMethod GetInitial(Output content)
{
Set content($Increment(content)) = ..#CustomCode
Do ..AppendStart(.content)
Do ..AppendLangExt1(.content)
Do ..AppendEnd(.content)
Set content($Increment(content)) = ..#CustomCode
}

}

0 comments on commit 983bf03

Please sign in to comment.