Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homeserver version without patch number parsing #6214

Merged
merged 7 commits into from
Jun 6, 2022

Conversation

ouchadam
Copy link
Contributor

@ouchadam ouchadam commented May 31, 2022

Type of change

  • Feature
  • Bugfix
  • Technical
  • Other :

Content

Fixes #6017 Supporting Homeserver versions without a patch number.

Versions without a patch are considered as having a patch of 0 eg 1.5 is parsed as major: 1 minor: 5 patch: 0

  • Makes the Homeserver version regex support optional patch numbers
  • Adds unit tests around the parsing

Motivation and context

To support version formats defined by the spec

Screenshots / GIFs

No UI changes

Tests

Handled by unit tests

Tested devices

  • Physical
  • Emulator
  • OS version(s): 28

@ouchadam ouchadam added matrix-sdk PR-Small PR with less than 20 updated lines labels May 31, 2022
@@ -38,14 +38,14 @@ internal data class HomeServerVersion(
}

companion object {
internal val pattern = Regex("""[r|v](\d+)\.(\d+)\.(\d+)""")
internal val pattern = Regex("""[r|v](\d+)\.(\d+)(?:\.(\d+))?""")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the fix, to make the last capture group optional

Copy link
Member

@bmarty bmarty May 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work, but strange that it's not just [r|v](\d+)\.(\d+)(\.(\d+))?. Regex syntax I guess.
EDIT: I see, it's to avoid the group to be captured. TIL

(supportedVersions + unsupportedVersions).forEach { (input, expected) ->
val result = HomeServerVersion.parse(input)

assertEquals(expected, result, "Expected $input to be $expected but got $result")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up using the assertEquals directly instead of shouldBeEqual in order to provide a custom message

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am always bitten by the parameter ordering. With JUnit the message is first.

Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Some remarks.

@@ -38,14 +38,14 @@ internal data class HomeServerVersion(
}

companion object {
internal val pattern = Regex("""[r|v](\d+)\.(\d+)\.(\d+)""")
internal val pattern = Regex("""[r|v](\d+)\.(\d+)(?:\.(\d+))?""")
Copy link
Member

@bmarty bmarty May 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work, but strange that it's not just [r|v](\d+)\.(\d+)(\.(\d+))?. Regex syntax I guess.
EDIT: I see, it's to avoid the group to be captured. TIL

(supportedVersions + unsupportedVersions).forEach { (input, expected) ->
val result = HomeServerVersion.parse(input)

assertEquals(expected, result, "Expected $input to be $expected but got $result")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am always bitten by the parameter ordering. With JUnit the message is first.

prefixes.map { prefix -> case.copy(input = "$prefix${case.input}") }
}.flatten()

private data class Case(val input: String, val expected: HomeServerVersion?)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OOI why all that private stuff is not inside class HomeServerVersionTest?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be inside the class, although there's nothing instance related in the helpers which is why I opted for having the helpers at the module level (I tend to lift pure functions out of classes)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point, thanks!

@@ -59,3 +59,5 @@ internal data class HomeServerVersion(
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
}
}

private fun List<String>.getOptional(index: Int, default: String) = getOrNull(index)?.ifEmpty { default } ?: default
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ifEmpty is maybe not necessary. I do not think it can be empty, since we have \d+. Maybe add a test with "v1.4.", expecting null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the optional block returns an empty string, with ifEmpty removed

java.lang.NumberFormatException: For input string: ""
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.base/java.lang.Integer.parseInt(Integer.java:662)
	at java.base/java.lang.Integer.parseInt(Integer.java:770)
	at org.matrix.android.sdk.internal.auth.version.HomeServerVersion$Companion.parse$matrix_sdk_android_debug(HomeServerVersion.kt:48)

have updated the test cases to include trailing . 4501c7c

Copy link
Member

@bmarty bmarty Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks. I would avoid creating this extension and would have written at line 48:

patch = result.groupValues.getOrNull(3)?.ensureNotEmpty()?.toInt() ?: 0

Since, this is not necessary to do "0".toInt().

The extension:

fun String.ensureNotEmpty() = takeIf { it.isNotEmpty() }

could be added to the core module package. I am surprised we do not have created it yet, we have 76 occurrences of .takeIf { it.isNotEmpty() } in the codebase :)

This is obviously not a blocker :).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add the extension to the sdk String extensions, currently there are no common modules between the app and the sdk

fa21b6d

case("1.5", expected = aVersion(1, 5, 0)),
case("0.5.1", expected = aVersion(0, 5, 1)),
case("1.0.0", expected = aVersion(1, 0, 0)),
case("1.10.3", expected = aVersion(1, 10, 3))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could have a trailing comma.

@github-actions
Copy link

github-actions bot commented May 31, 2022

Unit Test Results

148 files  +2  148 suites  +2   2m 15s ⏱️ -17s
237 tests +1  237 ✔️ +1  0 💤 ±0  0 ±0 
790 runs  +2  790 ✔️ +2  0 💤 ±0  0 ±0 

Results for commit fa21b6d. ± Comparison against base commit e6beb73.

♻️ This comment has been updated with latest results.

@ouchadam ouchadam force-pushed the feature/adm/homeserver-version-parsing branch from 30145c5 to 3756b2d Compare June 1, 2022 09:45
@@ -59,3 +59,5 @@ internal data class HomeServerVersion(
val v1_3_0 = HomeServerVersion(major = 1, minor = 3, patch = 0)
}
}

private fun List<String>.getOptional(index: Int, default: String) = getOrNull(index)?.ifEmpty { default } ?: default
Copy link
Member

@bmarty bmarty Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks. I would avoid creating this extension and would have written at line 48:

patch = result.groupValues.getOrNull(3)?.ensureNotEmpty()?.toInt() ?: 0

Since, this is not necessary to do "0".toInt().

The extension:

fun String.ensureNotEmpty() = takeIf { it.isNotEmpty() }

could be added to the core module package. I am surprised we do not have created it yet, we have 76 occurrences of .takeIf { it.isNotEmpty() } in the codebase :)

This is obviously not a blocker :).

@ouchadam ouchadam requested review from a team, ganfra and Claire1817 and removed request for a team and Claire1817 June 6, 2022 07:59
Copy link
Contributor

@ganfra ganfra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@ouchadam ouchadam enabled auto-merge June 6, 2022 13:51
@ouchadam ouchadam merged commit 0ef67b6 into develop Jun 6, 2022
@ouchadam ouchadam deleted the feature/adm/homeserver-version-parsing branch June 6, 2022 13:54
@github-actions
Copy link

github-actions bot commented Jun 6, 2022

Matrix SDK

Integration Tests Results:

  • [org.matrix.android.sdk.session]
    = passed=19 failures=1 errors=0 skipped=3
  • [org.matrix.android.sdk.account]
    = passed=3 failures=0 errors=0 skipped=2
  • [org.matrix.android.sdk.internal]
    = passed=27 failures=1 errors=0 skipped=1
  • [org.matrix.android.sdk.ordering]
    = passed=16 failures=0 errors=0 skipped=0
  • [org.matrix.android.sdk.PermalinkParserTest]
    = passed=16 failures=0 errors=0 skipped=0

/**
* Returns null if the string is empty.
*/
fun String.ensureNotEmpty() = ifEmpty { null }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, better than my proposal!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
matrix-sdk PR-Small PR with less than 20 updated lines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Homeserver version parser should support version without patch
3 participants