-
Notifications
You must be signed in to change notification settings - Fork 9
feat(CSAF2.1): #403 add mandatory test 6.2.39.2 - translation #413
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
Open
rainer-exxcellent
wants to merge
8
commits into
main
Choose a base branch
from
feat/403-csaf-2.1_recommended_test_6.2.39.2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9596ae1
feat(CSAF2.1): #403 add mandatory test 6.2.39.2
rainer-exxcellent e38cd73
feat(CSAF2.1): #401 add mandatory test 6.2.39.2 - move common functio…
rainer-exxcellent f5bace5
feat(CSAF2.1): #401 add mandatory test 6.2.39.2 - changed comment
rainer-exxcellent 2611bd4
feat(CSAF2.1): #401 add mandatory test 6.2.39.2 - use category constant
rainer-exxcellent 50398f0
feat(CSAF2.1): #403 add recommended test 6.2.39.2 - add info on no la…
rainer-exxcellent 5f7e541
refactor translation utils
domachine 175b0f6
feat(CSAF2.1): #403 add recommended test 6.2.39.2 - improve tests and…
rainer-exxcellent 07b1b79
feat(CSAF2.1): #403 add recommended test 6.2.39.2 - add regions and s…
rainer-exxcellent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| import Ajv from 'ajv/dist/jtd.js' | ||
| import { | ||
| containsOneNoteWithTitleAndCategory, | ||
| getTranslationInDocumentLang, | ||
| isLangSpecifiedAndNotEnglish, | ||
| } from '../../lib/shared/languageSpecificTranslation.js' | ||
|
|
||
| const ajv = new Ajv() | ||
|
|
||
| /* | ||
| This is the jtd schema that needs to match the input document so that the | ||
| test is activated. If this schema doesn't match it normally means that the input | ||
| document does not validate against the csaf json schema or optional fields that | ||
| the test checks are not present. | ||
| */ | ||
| const inputSchema = /** @type {const} */ ({ | ||
| additionalProperties: true, | ||
| properties: { | ||
| document: { | ||
| additionalProperties: true, | ||
| properties: { | ||
| category: { type: 'string' }, | ||
| }, | ||
| optionalProperties: { | ||
| lang: { | ||
| type: 'string', | ||
| }, | ||
| notes: { | ||
| elements: { | ||
| additionalProperties: true, | ||
| optionalProperties: { | ||
| category: { | ||
| type: 'string', | ||
| }, | ||
| title: { | ||
| type: 'string', | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
|
|
||
| const validateSchema = ajv.compile(inputSchema) | ||
|
|
||
| /** | ||
| * If the document language is specified but not English, it MUST be tested that exactly one item in document | ||
| * notes exists that has the language specific translation of the term Reasoning for Withdrawal as title. | ||
| * The category of this item MUST be description. If no language-specific translation has been recorded, | ||
| * the test MUST be skipped and output an information to the user that no such translation is known. | ||
| * | ||
| * @param {unknown} doc | ||
| */ | ||
| export function recommendedTest_6_2_39_2(doc) { | ||
| /* | ||
| The `ctx` variable holds the state that is accumulated during the test run and is | ||
| finally returned by the function. | ||
| */ | ||
| /** @type { {warnings: Array<{ message: string; instancePath: string }>; | ||
| * infos: Array<{ message: string; instancePath: string }>}} */ | ||
| const ctx = { | ||
| warnings: [], | ||
| infos: [], | ||
| } | ||
|
|
||
| const noteCategory = 'description' | ||
|
|
||
| if (!validateSchema(doc) || doc.document.category !== 'csaf_withdrawn') { | ||
| return ctx | ||
| } | ||
|
|
||
| const withdrawalInDocLang = getTranslationInDocumentLang( | ||
| doc, | ||
| 'reasoning_for_withdrawal' | ||
| ) | ||
| if (!withdrawalInDocLang) { | ||
| ctx.infos.push({ | ||
| instancePath: '/document/notes', | ||
| message: | ||
| 'no language specific translation for "Reasoning for Withdrawal" has been recorded', | ||
| }) | ||
| return ctx | ||
| } | ||
|
|
||
| if (isLangSpecifiedAndNotEnglish(doc.document.lang)) { | ||
| const notes = doc.document.notes | ||
| if ( | ||
| !notes || | ||
| !containsOneNoteWithTitleAndCategory( | ||
| notes, | ||
| withdrawalInDocLang, | ||
| noteCategory | ||
| ) | ||
| ) { | ||
| ctx.warnings.push({ | ||
| instancePath: '/document/notes', | ||
| message: | ||
| `for document category "csaf_withdrawn" exactly one note must exist ` + | ||
| `with note category "${noteCategory}" and title "${withdrawalInDocLang}`, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| return ctx | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| /** | ||
| * JavaScript version of JSON file: csaf_2.1/language_specific_translation/translations.json | ||
| */ | ||
| export default { | ||
| $schema: | ||
| 'https://raw.githubusercontent.com/oasis-tcs/csaf/master/csaf_2.1/test/language_specific_translation/translations_json_schema.json', | ||
| translation_version: '2.1', | ||
| translation: { | ||
| de: { | ||
| license: 'Lizenz', | ||
| product_description: 'Produktbeschreibung', | ||
| reasoning_for_supersession: 'Begründung für die Ersetzung', | ||
| reasoning_for_withdrawal: 'Begründung für die Zurückziehung', | ||
| superseding_document: 'Ersetzendes Dokument', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import bcp47 from 'bcp47' | ||
| import translations from '../../lib/language_specific_translation/translations.js' | ||
|
|
||
| const csafTranslationMaps = new Map( | ||
| Object.entries(translations.translation).map(([key, value]) => [ | ||
| key, | ||
| new Map(Object.entries(value)), | ||
| ]) | ||
| ) | ||
|
|
||
| /** | ||
| * Checks if the document language is specified and not English | ||
| * | ||
| * @param {string | undefined} language - The language expression to check | ||
| * @returns {boolean} False if language is English, true if the language is valid, false otherwise | ||
| */ | ||
| export function isLangSpecifiedAndNotEnglish(language) { | ||
| return ( | ||
| !!language && !(bcp47.parse(language)?.langtag.language.language === 'en') | ||
| ) | ||
| } | ||
|
|
||
| /** | ||
| * test whether exactly one item in document notes exists that has the given title. | ||
| * and the given category. | ||
| * @param {Array<{ category?: string | undefined; title?: string | undefined; }>} notes | ||
| * @param {string} titleToFind | ||
| * @param {string} category | ||
| * @returns {boolean} True if the language is valid, false otherwise | ||
| */ | ||
| export function containsOneNoteWithTitleAndCategory( | ||
| notes, | ||
| titleToFind, | ||
| category | ||
| ) { | ||
| return ( | ||
| notes.filter( | ||
| (note) => note.category === category && note.title === titleToFind | ||
| ).length === 1 | ||
| ) | ||
| } | ||
|
|
||
| /** | ||
| * Get the language specific translation of the given i18nKey | ||
| * @param {{ document: { lang?: string; }; }} doc | ||
| * @param {string} i18nKey | ||
| */ | ||
| export function getTranslationInDocumentLang(doc, i18nKey) { | ||
| return doc.document.lang | ||
| ? getTranslationInMap(doc.document.lang, i18nKey, csafTranslationMaps) | ||
| : undefined | ||
| } | ||
|
|
||
| /** | ||
| * Get the language specific translation of the given i18nKey in translationMaps | ||
| * @param {string} langToTranslate | ||
| * @param {string} i18nKey | ||
| * @param {Map<string,Map<string,string>>} translationMaps | ||
| */ | ||
| export function getTranslationInMap(langToTranslate, i18nKey, translationMaps) { | ||
| const langtag = bcp47.parse(langToTranslate)?.langtag | ||
| const languageCode = langtag?.language.language | ||
| let transMapForLanguage | ||
| if (langtag && languageCode) { | ||
| if (langtag.region) { | ||
| if (langtag.script) { | ||
| transMapForLanguage = translationMaps.get( | ||
| `${languageCode}-${langtag.script}-${langtag.region}` | ||
| ) | ||
| } | ||
| transMapForLanguage = | ||
| transMapForLanguage ?? | ||
| translationMaps.get(`${languageCode}-${langtag.region}`) | ||
| } | ||
| transMapForLanguage = | ||
| transMapForLanguage ?? translationMaps.get(languageCode) | ||
| } | ||
| return transMapForLanguage?.get(i18nKey) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,7 +43,6 @@ const excluded = [ | |
| '6.2.36', | ||
| '6.2.37', | ||
| '6.2.39.1', | ||
| '6.2.39.2', | ||
| '6.2.39.3', | ||
| '6.2.39.4', | ||
| '6.2.40', | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import { recommendedTest_6_2_39_2 } from '../../csaf_2_1/recommendedTests/recommendedTest_6_2_39_2.js' | ||
| import { expect } from 'chai' | ||
| import assert from 'node:assert' | ||
| import { getTranslationInDocumentLang } from '../../lib/shared/languageSpecificTranslation.js' | ||
|
|
||
| describe('recommendedTest_6_2_39_2', function () { | ||
| it('only runs on relevant documents', function () { | ||
| assert.equal(recommendedTest_6_2_39_2({}).warnings.length, 0) | ||
| }) | ||
|
|
||
| it('only runs on valid category', function () { | ||
| const result = recommendedTest_6_2_39_2({ | ||
| document: { category: '123', license_expression: 'MIT' }, | ||
| }) | ||
|
|
||
| assert.equal(result.warnings.length, 0) | ||
| assert.equal(result.infos.length, 0) | ||
| }) | ||
|
|
||
| it('info on invalid language', function () { | ||
| const result = recommendedTest_6_2_39_2({ | ||
| document: { | ||
| category: 'csaf_withdrawn', | ||
| lang: '123', | ||
| license_expression: 'MIT', | ||
| }, | ||
| }) | ||
| assert.equal(result.warnings.length, 0) | ||
| assert.equal(result.infos.length, 1) | ||
| }) | ||
|
|
||
| it('check get ReasoningForWithdrawal in document lang', function () { | ||
| expect( | ||
| getTranslationInDocumentLang( | ||
| { document: { lang: 'de' } }, | ||
| 'reasoning_for_withdrawal' | ||
| ) | ||
| ).to.eq('Begründung für die Zurückziehung') | ||
| expect( | ||
| getTranslationInDocumentLang( | ||
| { document: { lang: 'es' } }, | ||
| 'reasoning_for_withdrawal' | ||
| ) | ||
| ).to.eq(undefined) | ||
| expect( | ||
| getTranslationInDocumentLang({ document: {} }, 'reasoning_for_withdrawal') | ||
| ).to.eq(undefined) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { getTranslationInMap } from '../lib/shared/languageSpecificTranslation.js' | ||
| import { expect } from 'chai' | ||
|
|
||
| describe('test language specific translation', function () { | ||
| it('test getTranslationInMap', function () { | ||
| const translationMaps = new Map([ | ||
| ['de', new Map([['I18nTestKey', 'translationDe']])], | ||
| ['de-AT', new Map([['I18nTestKey', 'translationAT']])], | ||
| ['en', new Map([['I18nTestKey', 'translationEn']])], | ||
| ['zh-Hans-CN', new Map([['I18nTestKey', 'translationZh-Hans-CN']])], | ||
| ['sr', new Map([['I18nTestKey', 'translationSr']])], | ||
| ]) | ||
|
|
||
| expect( | ||
| getTranslationInMap('de', 'I18nTestKey', translationMaps), | ||
| 'Translate language code de' | ||
| ).to.equal('translationDe') | ||
| expect( | ||
| getTranslationInMap('de-AT', 'I18nTestKey', translationMaps), | ||
| 'Translate language and region code' | ||
| ).to.equal('translationAT') | ||
| expect( | ||
| getTranslationInMap('en', 'I18nTestKey', translationMaps), | ||
| 'Translate language code en' | ||
| ).to.equal('translationEn') | ||
| expect( | ||
| getTranslationInMap('en-US', 'I18nTestKey', translationMaps), | ||
| 'Fallback to language code en on region us' | ||
| ).to.equal('translationEn') | ||
| expect( | ||
| getTranslationInMap('zh-Hans-CN', 'I18nTestKey', translationMaps), | ||
| 'Translate language, region and script code' | ||
| ).to.equal('translationZh-Hans-CN') | ||
| expect( | ||
| getTranslationInMap('sr-Cyrl-RS', 'I18nTestKey', translationMaps), | ||
| 'Fallback to language code en on region an sript code' | ||
| ).to.equal('translationSr') | ||
| }) | ||
| }) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.