test(appstore): add test cases for appinfo.xml

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen 2026-05-12 22:22:40 +02:00
parent 21426974b1
commit 2b2b9840b8
No known key found for this signature in database
GPG key ID: 7E849AE05218500F
17 changed files with 1126 additions and 38 deletions

View file

@ -470,9 +470,8 @@ class OC_App {
}
}
$info['license'] ??= $info['licence'];
$info['license'] = $info['licence'];
$info['version'] = $appManager->getAppVersion($app);
$info['license'] ??= $info['licence'];
$appList[] = $info;
}
}

View file

@ -0,0 +1,162 @@
{
"id": "attributes_once",
"name": {
"@attributes": {
"lang": "en"
},
"@value": "Attributes Once"
},
"summary": {
"@attributes": {
"lang": "en"
},
"@value": "Single occurrence with attributes set on allowed elements."
},
"description": {
"@attributes": {
"lang": "en"
},
"@value": "Fixture that sets attributes where allowed (e.g., lang, type, min-version, for)."
},
"version": "1.2.3",
"licence": "agpl",
"author": {
"@attributes": {
"homepage": "http://example.com",
"mail": "jane@example.com"
},
"@value": "Jane Doe"
},
"types": [
"filesystem"
],
"documentation": {
"user": "https://example.test/attributes-once/user"
},
"category": [
"tools"
],
"website": "https://example.test/attributes-once",
"bugs": "https://example.com/issues",
"repository": {
"@attributes": {
"type": "git"
},
"@value": "https://example.test/attributes-once.git"
},
"screenshot": {
"@attributes": {
"small-thumbnail": "https://example.test/attributes-once-small.png"
},
"@value": "https://example.test/attributes-once.png"
},
"dependencies": {
"php": {
"@attributes": {
"min-version": "8.2"
}
},
"database": {
"@attributes": {
"min-version": "2.0"
},
"@value": "pgsql"
},
"lib": {
"@attributes": {
"min-version": "1.5"
},
"@value": "curl"
},
"owncloud": {
"@attributes": {
"min-version": "1.0",
"max-version": "2.0"
}
},
"nextcloud": {
"@attributes": {
"min-version": "30.0",
"max-version": "31.0"
}
},
"backend": [
"caldav"
]
},
"background-jobs": {
"job": "OCA\\AttributesOnce\\BackgroundJob\\Job"
},
"repair-steps": {
"install": {
"step": "OCA\\AttributesOnce\\RepairStep\\Install"
},
"pre-migration": [],
"post-migration": [],
"live-migration": [],
"uninstall": []
},
"commands": {
"command": "OCA\\AttributesOnce\\Command\\Run"
},
"settings": {
"admin": [
"OCA\\AttributesOnce\\Settings\\Admin"
],
"admin-section": [],
"personal": [],
"personal-section": []
},
"activity": {
"providers": {
"provider": "OCA\\AttributesOnce\\Activity\\Provider"
},
"filters": [],
"settings": []
},
"navigations": {
"navigation": [
{
"@attributes": {
"role": "admin"
},
"name": "Attributes",
"route": "attributes.once.route",
"icon": "attributes-once.svg",
"order": "5"
}
]
},
"collaboration": {
"plugins": {
"@attributes": {
"type": "collaborator-search"
},
"@value": "OCA\\AttributesOnce\\Collaboration\\Plugin"
}
},
"sabre": {
"plugins": {
"plugin": "OCA\\AttributesOnce\\Sabre\\Plugin"
}
},
"trash": {
"backend": {
"@attributes": {
"for": "files"
},
"@value": "OCA\\AttributesOnce\\Trash\\Backend"
}
},
"versions": {
"backend": {
"@attributes": {
"for": "files"
},
"@value": "OCA\\AttributesOnce\\Versions\\Backend"
}
},
"remote": [],
"public": [],
"two-factor-providers": []
}

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
SPDX-License-Identifier: AGPL-3.0-or-later

View file

@ -0,0 +1,77 @@
<?xml version="1.0"?>
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>attributes_once</id>
<name lang="en">Attributes Once</name>
<summary lang="en">Single occurrence with attributes set on allowed elements.</summary>
<description lang="en">Fixture that sets attributes where allowed (e.g., lang, type, min-version, for).</description>
<version>1.2.3</version>
<licence>agpl</licence>
<author homepage="http://example.com" mail="jane@example.com">Jane Doe</author>
<types>
<filesystem/>
</types>
<documentation>
<user>https://example.test/attributes-once/user</user>
</documentation>
<category>tools</category>
<website>https://example.test/attributes-once</website>
<bugs>https://example.com/issues</bugs>
<repository type="git">https://example.test/attributes-once.git</repository>
<screenshot small-thumbnail="https://example.test/attributes-once-small.png">https://example.test/attributes-once.png</screenshot>
<dependencies>
<php min-version="8.2"/>
<database min-version="2.0">pgsql</database>
<lib min-version="1.5">curl</lib>
<owncloud min-version="1.0" max-version="2.0"/>
<nextcloud min-version="30.0" max-version="31.0"/>
<backend>caldav</backend>
</dependencies>
<background-jobs>
<job>OCA\AttributesOnce\BackgroundJob\Job</job>
</background-jobs>
<repair-steps>
<install>
<step>OCA\AttributesOnce\RepairStep\Install</step>
</install>
</repair-steps>
<commands>
<command>OCA\AttributesOnce\Command\Run</command>
</commands>
<settings>
<admin>OCA\AttributesOnce\Settings\Admin</admin>
</settings>
<activity>
<providers>
<provider>OCA\AttributesOnce\Activity\Provider</provider>
</providers>
</activity>
<navigations>
<navigation role="admin">
<name>Attributes</name>
<route>attributes.once.route</route>
<icon>attributes-once.svg</icon>
<order>5</order>
</navigation>
</navigations>
<collaboration>
<plugins>
<plugin type="collaborator-search">OCA\AttributesOnce\Collaboration\Plugin</plugin>
</plugins>
</collaboration>
<sabre>
<plugins>
<plugin>OCA\AttributesOnce\Sabre\Plugin</plugin>
</plugins>
</sabre>
<trash>
<backend for="files">OCA\AttributesOnce\Trash\Backend</backend>
</trash>
<versions>
<backend for="files">OCA\AttributesOnce\Versions\Backend</backend>
</versions>
</info>

View file

@ -0,0 +1,192 @@
{
"id": "multi_once",
"name": "Multi Once",
"summary": "Every repeatable element is used exactly once.",
"description": "Fixture that exercises the single-item normalization path.",
"version": "1.0.0",
"licence": "agpl",
"author": [
"Jane Doe"
],
"types": [
"filesystem",
"logging"
],
"documentation": {
"user": "https://example.test/multi-once/user",
"admin": "https://example.test/multi-once/admin",
"developer": "https://example.test/multi-once/developer"
},
"category": [
"monitoring"
],
"website": "https://example.test/multi-once",
"discussion": "https://example.test/multi-once/discussion",
"bugs": "https://example.test/multi-once/issues",
"repository": "https://example.test/multi-once.git",
"screenshot": [
"https://example.test/multi-once.png"
],
"donation": "https://example.test/donate",
"dependencies": {
"database": "sqlite",
"command": "awk",
"lib": {
"@attributes": {
"min-version": "1.0"
},
"@value": "curl"
},
"nextcloud": {
"@attributes": {
"min-version": "30.0",
"max-version": "31.0"
}
},
"architecture": "x86_64",
"backend": [
"caldav"
]
},
"background-jobs": {
"job": "OCA\\MultiOnce\\BackgroundJob\\Cleanup"
},
"repair-steps": {
"pre-migration": {
"step": "OCA\\MultiOnce\\RepairStep\\PreMigration"
},
"post-migration": {
"step": "OCA\\MultiOnce\\RepairStep\\PostMigration"
},
"live-migration": {
"step": "OCA\\MultiOnce\\RepairStep\\LiveMigration"
},
"install": {
"step": "OCA\\MultiOnce\\RepairStep\\Install"
},
"uninstall": {
"step": "OCA\\MultiOnce\\RepairStep\\Uninstall"
}
},
"two-factor-providers": {
"provider": "OCA\\MultiOnce\\TwoFactor\\Provider"
},
"commands": {
"command": "OCA\\MultiOnce\\Command\\Migrate"
},
"settings": {
"admin": [
"OCA\\MultiOnce\\Settings\\Admin"
],
"admin-section": [
"OCA\\MultiOnce\\Settings\\AdminSection"
],
"personal": [
"OCA\\MultiOnce\\Settings\\Personal"
],
"personal-section": [
"OCA\\MultiOnce\\Settings\\PersonalSection"
],
"admin-delegation": [
"OCA\\MultiOnce\\Settings\\AdminDelegation"
],
"admin-delegation-section": [
"OCA\\MultiOnce\\Settings\\AdminDelegationSection"
]
},
"activity": {
"settings": {
"setting": "OCA\\MultiOnce\\Activity\\Setting"
},
"filters": {
"filter": "OCA\\MultiOnce\\Activity\\Filter"
},
"providers": {
"provider": "OCA\\MultiOnce\\Activity\\Provider"
}
},
"dashboard": {
"widget": "OCA\\MultiOnce\\Dashboard\\Widget"
},
"fulltextsearch": {
"platform": "OCA\\MultiOnce\\Search\\Platform",
"provider": "OCA\\MultiOnce\\Search\\Provider"
},
"navigations": {
"navigation": [
{
"name": "Multi Once",
"route": "multi.once.route",
"icon": "multi-once.svg",
"order": "1"
}
]
},
"contactsmenu": {
"provider": "OCA\\MultiOnce\\ContactsMenu\\Provider"
},
"collaboration": {
"plugins": {
"@attributes": {
"type": "collaborator-search"
},
"@value": "OCA\\MultiOnce\\Collaboration\\Plugin"
}
},
"openmetrics": {
"exporter": [
"OCA\\MultiOnce\\OpenMetrics\\Exporter"
]
},
"sabre": {
"collections": {
"collection": "OCA\\MultiOnce\\Sabre\\Collection"
},
"plugins": {
"plugin": "OCA\\MultiOnce\\Sabre\\Plugin"
},
"address-book-plugins": {
"plugin": "OCA\\MultiOnce\\Sabre\\AddressBookPlugin"
},
"calendar-plugins": {
"plugin": "OCA\\MultiOnce\\Sabre\\CalendarPlugin"
}
},
"trash": {
"backend": {
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiOnce\\Trash\\Backend"
}
},
"versions": {
"backend": {
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiOnce\\Versions\\Backend"
}
},
"external-app": {
"docker-install": {
"registry": "registry.example.test",
"image": "multi-once",
"image-tag": "1.0.0"
},
"scopes": {
"value": "scope-one"
},
"system": "true",
"environment-variables": {
"variable": {
"name": "MULTI_ONCE_ONE",
"display-name": "Multi Once One",
"description": "First variable",
"default": "one"
}
}
},
"remote": [],
"public": []
}

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
SPDX-License-Identifier: AGPL-3.0-or-later

View file

@ -0,0 +1,149 @@
<?xml version="1.0"?>
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>multi_once</id>
<name>Multi Once</name>
<summary>Every repeatable element is used exactly once.</summary>
<description>Fixture that exercises the single-item normalization path.</description>
<version>1.0.0</version>
<licence>agpl</licence>
<author>Jane Doe</author>
<types>
<filesystem/>
<logging/>
</types>
<documentation>
<user>https://example.test/multi-once/user</user>
<admin>https://example.test/multi-once/admin</admin>
<developer>https://example.test/multi-once/developer</developer>
</documentation>
<category>monitoring</category>
<website>https://example.test/multi-once</website>
<discussion>https://example.test/multi-once/discussion</discussion>
<bugs>https://example.test/multi-once/issues</bugs>
<repository>https://example.test/multi-once.git</repository>
<screenshot>https://example.test/multi-once.png</screenshot>
<donation>https://example.test/donate</donation>
<dependencies>
<database>sqlite</database>
<command>awk</command>
<lib min-version="1.0">curl</lib>
<nextcloud min-version="30.0" max-version="31.0"/>
<architecture>x86_64</architecture>
<backend>caldav</backend>
</dependencies>
<background-jobs>
<job>OCA\MultiOnce\BackgroundJob\Cleanup</job>
</background-jobs>
<repair-steps>
<pre-migration>
<step>OCA\MultiOnce\RepairStep\PreMigration</step>
</pre-migration>
<post-migration>
<step>OCA\MultiOnce\RepairStep\PostMigration</step>
</post-migration>
<live-migration>
<step>OCA\MultiOnce\RepairStep\LiveMigration</step>
</live-migration>
<install>
<step>OCA\MultiOnce\RepairStep\Install</step>
</install>
<uninstall>
<step>OCA\MultiOnce\RepairStep\Uninstall</step>
</uninstall>
</repair-steps>
<two-factor-providers>
<provider>OCA\MultiOnce\TwoFactor\Provider</provider>
</two-factor-providers>
<commands>
<command>OCA\MultiOnce\Command\Migrate</command>
</commands>
<settings>
<admin>OCA\MultiOnce\Settings\Admin</admin>
<admin-section>OCA\MultiOnce\Settings\AdminSection</admin-section>
<personal>OCA\MultiOnce\Settings\Personal</personal>
<personal-section>OCA\MultiOnce\Settings\PersonalSection</personal-section>
<admin-delegation>OCA\MultiOnce\Settings\AdminDelegation</admin-delegation>
<admin-delegation-section>OCA\MultiOnce\Settings\AdminDelegationSection</admin-delegation-section>
</settings>
<activity>
<settings>
<setting>OCA\MultiOnce\Activity\Setting</setting>
</settings>
<filters>
<filter>OCA\MultiOnce\Activity\Filter</filter>
</filters>
<providers>
<provider>OCA\MultiOnce\Activity\Provider</provider>
</providers>
</activity>
<dashboard>
<widget>OCA\MultiOnce\Dashboard\Widget</widget>
</dashboard>
<fulltextsearch>
<platform>OCA\MultiOnce\Search\Platform</platform>
<provider>OCA\MultiOnce\Search\Provider</provider>
</fulltextsearch>
<navigations>
<navigation>
<name>Multi Once</name>
<route>multi.once.route</route>
<icon>multi-once.svg</icon>
<order>1</order>
</navigation>
</navigations>
<contactsmenu>
<provider>OCA\MultiOnce\ContactsMenu\Provider</provider>
</contactsmenu>
<collaboration>
<plugins>
<plugin type="collaborator-search">OCA\MultiOnce\Collaboration\Plugin</plugin>
</plugins>
</collaboration>
<openmetrics>
<exporter>OCA\MultiOnce\OpenMetrics\Exporter</exporter>
</openmetrics>
<sabre>
<collections>
<collection>OCA\MultiOnce\Sabre\Collection</collection>
</collections>
<plugins>
<plugin>OCA\MultiOnce\Sabre\Plugin</plugin>
</plugins>
<address-book-plugins>
<plugin>OCA\MultiOnce\Sabre\AddressBookPlugin</plugin>
</address-book-plugins>
<calendar-plugins>
<plugin>OCA\MultiOnce\Sabre\CalendarPlugin</plugin>
</calendar-plugins>
</sabre>
<trash>
<backend for="files">OCA\MultiOnce\Trash\Backend</backend>
</trash>
<versions>
<backend for="files">OCA\MultiOnce\Versions\Backend</backend>
</versions>
<external-app>
<docker-install>
<registry>registry.example.test</registry>
<image>multi-once</image>
<image-tag>1.0.0</image-tag>
</docker-install>
<scopes>
<value>scope-one</value>
</scopes>
<system>true</system>
<environment-variables>
<variable>
<name>MULTI_ONCE_ONE</name>
<display-name>Multi Once One</display-name>
<description>First variable</description>
<default>one</default>
</variable>
</environment-variables>
</external-app>
</info>

View file

@ -0,0 +1,325 @@
{
"id": "multi_twice",
"name": "Multi Twice",
"summary": "Every repeatable element is used exactly twice.",
"description": "Fixture that exercises the list normalization path.",
"version": "1.0.0",
"licence": [
"agpl",
"mit"
],
"author": [
"Jane Doe",
"John Doe"
],
"types": [
"filesystem",
"logging"
],
"documentation": {
"user": "https://example.test/multi-twice/user",
"admin": "https://example.test/multi-twice/admin",
"developer": "https://example.test/multi-twice/developer"
},
"category": [
"monitoring",
"social"
],
"website": "https://example.test/multi-twice",
"discussion": "https://example.test/multi-twice/discussion",
"bugs": "https://example.test/multi-twice/issues",
"repository": {
"@attributes": {
"type": "git"
},
"@value": "https://example.test/multi-twice.git"
},
"screenshot": [
"https://example.test/multi-twice-1.png",
"https://example.test/multi-twice-2.png"
],
"donation": [
"https://example.test/donate/1",
"https://example.test/donate/2"
],
"dependencies": {
"php": {
"@attributes": {
"min-version": "8.2"
}
},
"database": [
{
"@attributes": {
"min-version": "1.0"
},
"@value": "sqlite"
},
{
"@attributes": {
"min-version": "1.0"
},
"@value": "mysql"
}
],
"command": [
"awk",
"grep"
],
"lib": [
{
"@attributes": {
"min-version": "1.0"
},
"@value": "curl"
},
{
"@attributes": {
"min-version": "1.0"
},
"@value": "intl"
}
],
"owncloud": {
"@attributes": {
"min-version": "1.0",
"max-version": "2.0"
}
},
"nextcloud": {
"@attributes": {
"min-version": "30.0",
"max-version": "31.0"
}
},
"architecture": [
"x86_64",
"aarch64"
],
"backend": [
"caldav",
"caldav"
]
},
"background-jobs": [
"OCA\\MultiTwice\\BackgroundJob\\CleanupOne",
"OCA\\MultiTwice\\BackgroundJob\\CleanupTwo"
],
"repair-steps": {
"pre-migration": [
"OCA\\MultiTwice\\RepairStep\\PreMigrationOne",
"OCA\\MultiTwice\\RepairStep\\PreMigrationTwo"
],
"post-migration": [
"OCA\\MultiTwice\\RepairStep\\PostMigrationOne",
"OCA\\MultiTwice\\RepairStep\\PostMigrationTwo"
],
"live-migration": [
"OCA\\MultiTwice\\RepairStep\\LiveMigrationOne",
"OCA\\MultiTwice\\RepairStep\\LiveMigrationTwo"
],
"install": [
"OCA\\MultiTwice\\RepairStep\\InstallOne",
"OCA\\MultiTwice\\RepairStep\\InstallTwo"
],
"uninstall": [
"OCA\\MultiTwice\\RepairStep\\UninstallOne",
"OCA\\MultiTwice\\RepairStep\\UninstallTwo"
]
},
"two-factor-providers": [
"OCA\\MultiTwice\\TwoFactor\\ProviderOne",
"OCA\\MultiTwice\\TwoFactor\\ProviderTwo"
],
"commands": [
"OCA\\MultiTwice\\Command\\MigrateOne",
"OCA\\MultiTwice\\Command\\MigrateTwo"
],
"settings": {
"admin": [
"OCA\\MultiTwice\\Settings\\AdminOne",
"OCA\\MultiTwice\\Settings\\AdminTwo"
],
"admin-section": [
"OCA\\MultiTwice\\Settings\\AdminSectionOne",
"OCA\\MultiTwice\\Settings\\AdminSectionTwo"
],
"personal": [
"OCA\\MultiTwice\\Settings\\PersonalOne",
"OCA\\MultiTwice\\Settings\\PersonalTwo"
],
"personal-section": [
"OCA\\MultiTwice\\Settings\\PersonalSectionOne",
"OCA\\MultiTwice\\Settings\\PersonalSectionTwo"
],
"admin-delegation": [
"OCA\\MultiTwice\\Settings\\AdminDelegationOne",
"OCA\\MultiTwice\\Settings\\AdminDelegationTwo"
],
"admin-delegation-section": [
"OCA\\MultiTwice\\Settings\\AdminDelegationSectionOne",
"OCA\\MultiTwice\\Settings\\AdminDelegationSectionTwo"
]
},
"activity": {
"settings": [
"OCA\\MultiTwice\\Activity\\SettingOne",
"OCA\\MultiTwice\\Activity\\SettingTwo"
],
"filters": [
"OCA\\MultiTwice\\Activity\\FilterOne",
"OCA\\MultiTwice\\Activity\\FilterTwo"
],
"providers": [
"OCA\\MultiTwice\\Activity\\ProviderOne",
"OCA\\MultiTwice\\Activity\\ProviderTwo"
]
},
"dashboard": {
"widget": [
"OCA\\MultiTwice\\Dashboard\\WidgetOne",
"OCA\\MultiTwice\\Dashboard\\WidgetTwo"
]
},
"fulltextsearch": {
"platform": [
"OCA\\MultiTwice\\Search\\PlatformOne",
"OCA\\MultiTwice\\Search\\PlatformTwo"
],
"provider": [
"OCA\\MultiTwice\\Search\\ProviderOne",
"OCA\\MultiTwice\\Search\\ProviderTwo"
]
},
"navigations": {
"navigation": [
{
"name": "Multi Twice One",
"route": "multi.twice.one",
"icon": "multi-twice-1.svg",
"order": "1"
},
{
"name": "Multi Twice Two",
"route": "multi.twice.two",
"icon": "multi-twice-2.svg",
"order": "2"
}
]
},
"contactsmenu": {
"provider": "OCA\\MultiTwice\\ContactsMenu\\Provider"
},
"collaboration": {
"plugins": [
{
"@attributes": {
"type": "collaborator-search"
},
"@value": "OCA\\MultiTwice\\Collaboration\\PluginOne"
},
{
"@attributes": {
"type": "autocomplete-sort"
},
"@value": "OCA\\MultiTwice\\Collaboration\\PluginTwo"
}
]
},
"openmetrics": {
"exporter": [
"OCA\\MultiTwice\\OpenMetrics\\ExporterOne",
"OCA\\MultiTwice\\OpenMetrics\\ExporterTwo"
]
},
"sabre": {
"collections": {
"collection": [
"OCA\\MultiTwice\\Sabre\\CollectionOne",
"OCA\\MultiTwice\\Sabre\\CollectionTwo"
]
},
"plugins": {
"plugin": [
"OCA\\MultiTwice\\Sabre\\PluginOne",
"OCA\\MultiTwice\\Sabre\\PluginTwo"
]
},
"address-book-plugins": {
"plugin": [
"OCA\\MultiTwice\\Sabre\\AddressBookPluginOne",
"OCA\\MultiTwice\\Sabre\\AddressBookPluginTwo"
]
},
"calendar-plugins": {
"plugin": [
"OCA\\MultiTwice\\Sabre\\CalendarPluginOne",
"OCA\\MultiTwice\\Sabre\\CalendarPluginTwo"
]
}
},
"trash": {
"backend": [
{
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiTwice\\Trash\\BackendOne"
},
{
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiTwice\\Trash\\BackendTwo"
}
]
},
"versions": {
"backend": [
{
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiTwice\\Versions\\BackendOne"
},
{
"@attributes": {
"for": "files"
},
"@value": "OCA\\MultiTwice\\Versions\\BackendTwo"
}
]
},
"external-app": {
"docker-install": {
"registry": "registry.example.test",
"image": "multi-twice",
"image-tag": "2.0.0"
},
"scopes": {
"value": [
"scope-one",
"scope-two"
]
},
"system": "true",
"environment-variables": {
"variable": [
{
"name": "MULTI_TWICE_ONE",
"display-name": "Multi Twice One",
"description": "First variable",
"default": "one"
},
{
"name": "MULTI_TWICE_TWO",
"display-name": "Multi Twice Two",
"description": "Second variable",
"default": "two"
}
]
}
},
"remote": [],
"public": []
}

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
SPDX-License-Identifier: AGPL-3.0-or-later

View file

@ -0,0 +1,202 @@
<?xml version="1.0"?>
<!--
- SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>multi_twice</id>
<name>Multi Twice</name>
<summary>Every repeatable element is used exactly twice.</summary>
<description>Fixture that exercises the list normalization path.</description>
<version>1.0.0</version>
<licence>agpl</licence>
<licence>mit</licence>
<author>Jane Doe</author>
<author>John Doe</author>
<types>
<filesystem/>
<logging/>
</types>
<documentation>
<user>https://example.test/multi-twice/user</user>
<admin>https://example.test/multi-twice/admin</admin>
<developer>https://example.test/multi-twice/developer</developer>
</documentation>
<category>monitoring</category>
<category>social</category>
<website>https://example.test/multi-twice</website>
<discussion>https://example.test/multi-twice/discussion</discussion>
<bugs>https://example.test/multi-twice/issues</bugs>
<repository type="git">https://example.test/multi-twice.git</repository>
<screenshot>https://example.test/multi-twice-1.png</screenshot>
<screenshot>https://example.test/multi-twice-2.png</screenshot>
<donation>https://example.test/donate/1</donation>
<donation>https://example.test/donate/2</donation>
<dependencies>
<php min-version="8.2"/>
<database min-version="1.0">sqlite</database>
<database min-version="1.0">mysql</database>
<command>awk</command>
<command>grep</command>
<lib min-version="1.0">curl</lib>
<lib min-version="1.0">intl</lib>
<owncloud min-version="1.0" max-version="2.0"/>
<nextcloud min-version="30.0" max-version="31.0"/>
<architecture>x86_64</architecture>
<architecture>aarch64</architecture>
<backend>caldav</backend>
<backend>caldav</backend>
</dependencies>
<background-jobs>
<job>OCA\MultiTwice\BackgroundJob\CleanupOne</job>
<job>OCA\MultiTwice\BackgroundJob\CleanupTwo</job>
</background-jobs>
<repair-steps>
<pre-migration>
<step>OCA\MultiTwice\RepairStep\PreMigrationOne</step>
<step>OCA\MultiTwice\RepairStep\PreMigrationTwo</step>
</pre-migration>
<post-migration>
<step>OCA\MultiTwice\RepairStep\PostMigrationOne</step>
<step>OCA\MultiTwice\RepairStep\PostMigrationTwo</step>
</post-migration>
<live-migration>
<step>OCA\MultiTwice\RepairStep\LiveMigrationOne</step>
<step>OCA\MultiTwice\RepairStep\LiveMigrationTwo</step>
</live-migration>
<install>
<step>OCA\MultiTwice\RepairStep\InstallOne</step>
<step>OCA\MultiTwice\RepairStep\InstallTwo</step>
</install>
<uninstall>
<step>OCA\MultiTwice\RepairStep\UninstallOne</step>
<step>OCA\MultiTwice\RepairStep\UninstallTwo</step>
</uninstall>
</repair-steps>
<two-factor-providers>
<provider>OCA\MultiTwice\TwoFactor\ProviderOne</provider>
<provider>OCA\MultiTwice\TwoFactor\ProviderTwo</provider>
</two-factor-providers>
<commands>
<command>OCA\MultiTwice\Command\MigrateOne</command>
<command>OCA\MultiTwice\Command\MigrateTwo</command>
</commands>
<settings>
<admin>OCA\MultiTwice\Settings\AdminOne</admin>
<admin>OCA\MultiTwice\Settings\AdminTwo</admin>
<admin-section>OCA\MultiTwice\Settings\AdminSectionOne</admin-section>
<admin-section>OCA\MultiTwice\Settings\AdminSectionTwo</admin-section>
<personal>OCA\MultiTwice\Settings\PersonalOne</personal>
<personal>OCA\MultiTwice\Settings\PersonalTwo</personal>
<personal-section>OCA\MultiTwice\Settings\PersonalSectionOne</personal-section>
<personal-section>OCA\MultiTwice\Settings\PersonalSectionTwo</personal-section>
<admin-delegation>OCA\MultiTwice\Settings\AdminDelegationOne</admin-delegation>
<admin-delegation>OCA\MultiTwice\Settings\AdminDelegationTwo</admin-delegation>
<admin-delegation-section>OCA\MultiTwice\Settings\AdminDelegationSectionOne</admin-delegation-section>
<admin-delegation-section>OCA\MultiTwice\Settings\AdminDelegationSectionTwo</admin-delegation-section>
</settings>
<activity>
<settings>
<setting>OCA\MultiTwice\Activity\SettingOne</setting>
<setting>OCA\MultiTwice\Activity\SettingTwo</setting>
</settings>
<filters>
<filter>OCA\MultiTwice\Activity\FilterOne</filter>
<filter>OCA\MultiTwice\Activity\FilterTwo</filter>
</filters>
<providers>
<provider>OCA\MultiTwice\Activity\ProviderOne</provider>
<provider>OCA\MultiTwice\Activity\ProviderTwo</provider>
</providers>
</activity>
<dashboard>
<widget>OCA\MultiTwice\Dashboard\WidgetOne</widget>
<widget>OCA\MultiTwice\Dashboard\WidgetTwo</widget>
</dashboard>
<fulltextsearch>
<platform>OCA\MultiTwice\Search\PlatformOne</platform>
<platform>OCA\MultiTwice\Search\PlatformTwo</platform>
<provider>OCA\MultiTwice\Search\ProviderOne</provider>
<provider>OCA\MultiTwice\Search\ProviderTwo</provider>
</fulltextsearch>
<navigations>
<navigation>
<name>Multi Twice One</name>
<route>multi.twice.one</route>
<icon>multi-twice-1.svg</icon>
<order>1</order>
</navigation>
<navigation>
<name>Multi Twice Two</name>
<route>multi.twice.two</route>
<icon>multi-twice-2.svg</icon>
<order>2</order>
</navigation>
</navigations>
<contactsmenu>
<provider>OCA\MultiTwice\ContactsMenu\Provider</provider>
</contactsmenu>
<collaboration>
<plugins>
<plugin type="collaborator-search">OCA\MultiTwice\Collaboration\PluginOne</plugin>
<plugin type="autocomplete-sort">OCA\MultiTwice\Collaboration\PluginTwo</plugin>
</plugins>
</collaboration>
<openmetrics>
<exporter>OCA\MultiTwice\OpenMetrics\ExporterOne</exporter>
<exporter>OCA\MultiTwice\OpenMetrics\ExporterTwo</exporter>
</openmetrics>
<sabre>
<collections>
<collection>OCA\MultiTwice\Sabre\CollectionOne</collection>
<collection>OCA\MultiTwice\Sabre\CollectionTwo</collection>
</collections>
<plugins>
<plugin>OCA\MultiTwice\Sabre\PluginOne</plugin>
<plugin>OCA\MultiTwice\Sabre\PluginTwo</plugin>
</plugins>
<address-book-plugins>
<plugin>OCA\MultiTwice\Sabre\AddressBookPluginOne</plugin>
<plugin>OCA\MultiTwice\Sabre\AddressBookPluginTwo</plugin>
</address-book-plugins>
<calendar-plugins>
<plugin>OCA\MultiTwice\Sabre\CalendarPluginOne</plugin>
<plugin>OCA\MultiTwice\Sabre\CalendarPluginTwo</plugin>
</calendar-plugins>
</sabre>
<trash>
<backend for="files">OCA\MultiTwice\Trash\BackendOne</backend>
<backend for="files">OCA\MultiTwice\Trash\BackendTwo</backend>
</trash>
<versions>
<backend for="files">OCA\MultiTwice\Versions\BackendOne</backend>
<backend for="files">OCA\MultiTwice\Versions\BackendTwo</backend>
</versions>
<external-app>
<docker-install>
<registry>registry.example.test</registry>
<image>multi-twice</image>
<image-tag>2.0.0</image-tag>
</docker-install>
<scopes>
<value>scope-one</value>
<value>scope-two</value>
</scopes>
<system>true</system>
<environment-variables>
<variable>
<name>MULTI_TWICE_ONE</name>
<display-name>Multi Twice One</display-name>
<description>First variable</description>
<default>one</default>
</variable>
<variable>
<name>MULTI_TWICE_TWO</name>
<display-name>Multi Twice Two</display-name>
<description>Second variable</description>
<default>two</default>
</variable>
</environment-variables>
</external-app>
</info>

View file

@ -1,12 +0,0 @@
<?xml version="1.0"?>
<!--
- SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<info>
<id>files_encryption</id>
<name>Server-side Encryption</name>
<description lang="en">English</description>
<description lang="de">German</description>
<licence>AGPL</licence>
</info>

View file

@ -1,11 +0,0 @@
<?xml version="1.0"?>
<!--
- SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<info>
<id>files_encryption</id>
<name>Server-side Encryption</name>
<description lang="en">English</description>
<licence>AGPL</licence>
</info>

View file

@ -1,5 +1,4 @@
{
"info": [],
"remote": [],
"public": [],
"id": "files_encryption",

View file

@ -72,7 +72,6 @@
}
]
},
"info": [],
"remote": [],
"public": [],
"repair-steps": {

View file

@ -78,7 +78,6 @@
}
]
},
"info": [],
"remote": [],
"public": [],
"repair-steps": {

View file

@ -22,7 +22,6 @@
"category": [
"monitoring"
],
"info": [],
"background-jobs": [],
"activity": {
"filters": [],

View file

@ -47,16 +47,19 @@ class InfoParserTest extends TestCase {
#[\PHPUnit\Framework\Attributes\DataProvider('appDataProvider')]
public function testApplyL10N(array $data, array $expected, string $language): void {
$parser = new InfoParser();
$this->assertSame($expected, $parser->applyL10N($data, $language));
$this->assertEqualsCanonicalizing($expected, $parser->applyL10N($data, $language));
}
public static function providesInfoXml(): array {
return [
['expected-info.json', 'valid-info.xml'],
[null, 'invalid-info.xml'],
['navigation-one-item.json', 'navigation-one-item.xml'],
['navigation-two-items.json', 'navigation-two-items.xml'],
['various-single-item.json', 'various-single-item.xml'],
'Only one value in each list' => ['appinfo-multi-once.json', 'appinfo-multi-once.xml'],
'Only one value in each list with attributes' => ['appinfo-attributes-once.json', 'appinfo-attributes-once.xml'],
'Multiple values in each list' => ['appinfo-multi-twice.json', 'appinfo-multi-twice.xml'],
'Valid info' => ['expected-info.json', 'valid-info.xml'],
'Invalid info' => [null, 'invalid-info.xml'],
'Navigation one item' => ['navigation-one-item.json', 'navigation-one-item.xml'],
'Navigation two items' => ['navigation-two-items.json', 'navigation-two-items.xml'],
'Various single item' => ['various-single-item.json', 'various-single-item.xml'],
];
}
@ -83,17 +86,17 @@ class InfoParserTest extends TestCase {
// test trimming
[
['description' => " \t This is a multiline \n test with \n \t \n \n some new lines "],
['description' => "This is a multiline \n test with \n \t \n \n some new lines"],
['description' => "This is a multiline \n test with \n \t \n \n some new lines", 'summary' => '', 'name' => ''],
'en'
],
[
['description' => " \t This is a multiline \n test with \n \t some new lines "],
['description' => "This is a multiline \n test with \n \t some new lines"],
['description' => "This is a multiline \n test with \n \t some new lines", 'summary' => '', 'name' => ''],
'en'
],
[
['description' => hex2bin('5065726d657420646520732761757468656e7469666965722064616e732070697769676f20646972656374656d656e74206176656320736573206964656e74696669616e7473206f776e636c6f75642073616e73206c65732072657461706572206574206d657420c3a0206a6f757273206365757820636920656e20636173206465206368616e67656d656e74206465206d6f742064652070617373652e0d0a0d')],
['description' => "Permet de s'authentifier dans piwigo directement avec ses identifiants owncloud sans les retaper et met à jours ceux ci en cas de changement de mot de passe."],
['description' => "Permet de s'authentifier dans piwigo directement avec ses identifiants owncloud sans les retaper et met à jours ceux ci en cas de changement de mot de passe.", 'summary' => '', 'name' => ''],
'fr'
],
// test proper translation handling