From 344f8bcabe590a7ad493e38d775f382cb363c000 Mon Sep 17 00:00:00 2001 From: Thijs De Paepe Date: Tue, 24 Oct 2023 11:41:32 +0200 Subject: [PATCH] AKIMESKLIU-154/nnimports (#59) * action-improvements * added: EmptyAction test * added: FilterFieldAction, akeneo/product/csv revert option * added: ExtensionsAction * added: more flexible CSV product converter * fix: test: DateTimeAction::testConvertMappedFormatValidCase * added: more tests --- src/Component/Action/CopyAction.php | 11 +- src/Component/Action/EmptyAction.php | 5 + src/Component/Action/ExtensionAction.php | 46 +++++ src/Component/Action/FilterAction.php | 3 +- src/Component/Action/FilterFieldAction.php | 65 +++++++ .../Common/Cursor/ZoneFileIndexer.php | 8 +- .../Common/Pipeline/PipelineFactory.php | 6 + src/Component/Configurator/Configuration.php | 17 ++ .../Configurator/ConfigurationManager.php | 5 + .../Configurator/ReadOnlyConfiguration.php | 69 +++++++ .../Converter/Akeneo/Csv/Product.php | 74 ++++++-- .../Extension/ExtensionInterface.php | 8 + src/Component/Item/TypeGuesser.php | 9 + src/bootstrap.php | 2 + tests/Component/Action/DateTimeActionTest.php | 21 +++ tests/Component/Action/EmptyActionTest.php | 53 ++++++ .../Action/FilterFieldActionTest.php | 173 ++++++++++++++++++ tests/Component/Action/UnsetActionTest.php | 22 +++ .../Converter/Akeneo/Csv/ProductTest.php | 20 +- 19 files changed, 581 insertions(+), 36 deletions(-) create mode 100644 src/Component/Action/ExtensionAction.php create mode 100644 src/Component/Action/FilterFieldAction.php create mode 100644 src/Component/Configurator/ReadOnlyConfiguration.php create mode 100644 src/Component/Extension/ExtensionInterface.php create mode 100644 tests/Component/Action/EmptyActionTest.php create mode 100644 tests/Component/Action/FilterFieldActionTest.php diff --git a/src/Component/Action/CopyAction.php b/src/Component/Action/CopyAction.php index 6e135eba..8d7352cf 100644 --- a/src/Component/Action/CopyAction.php +++ b/src/Component/Action/CopyAction.php @@ -20,20 +20,23 @@ class CopyAction implements ActionInterface, OptionsInterface public function apply(array $item): array { - $matched = $this->findMatchedValueData($item, $this->options['from']); + $to = $this->getOption('to'); + $from = $this->getOption('from'); + + $matched = $this->findMatchedValueData($item, $from); if ($matched) { - $matcher = $item[$matched]['matcher']->duplicateWithNewKey($this->options['to']); + $matcher = $item[$matched]['matcher']->duplicateWithNewKey($to); $item[$matcher->getMainKey()] = $item[$matched]; $item[$matcher->getMainKey()]['matcher'] = $matcher; return $item; } - if (!isset($item[$this->options['from']])) { + if (!isset($item[$from])) { return $item; } - $item[$this->options['to']] = $item[$this->options['from']]; + $item[$to] = $item[$from]; return $item; } diff --git a/src/Component/Action/EmptyAction.php b/src/Component/Action/EmptyAction.php index f87e012c..ade012ec 100644 --- a/src/Component/Action/EmptyAction.php +++ b/src/Component/Action/EmptyAction.php @@ -10,6 +10,10 @@ /** * @deprecated * This action needs improvement, it's hardcoded to akeneo data + * EmptyAction clears values + * ATM it's action limited to akeneo data + * - It should support flat data fields + * - It should support Matched fields instead direct Akeneo API data */ class EmptyAction implements OptionsInterface, ConfigurationAwareInterface { @@ -22,6 +26,7 @@ class EmptyAction implements OptionsInterface, ConfigurationAwareInterface private $options = [ 'field' => null, 'list' => null, + 'prefix' => null, ]; public function apply(array $item): array diff --git a/src/Component/Action/ExtensionAction.php b/src/Component/Action/ExtensionAction.php new file mode 100644 index 00000000..e01bf5d1 --- /dev/null +++ b/src/Component/Action/ExtensionAction.php @@ -0,0 +1,46 @@ + null, + ]; + + public function apply($item): array + { + $extension = $this->getOption('extension'); + if (null === $extension) { + return $item; + } + // loadExtension + if (null === $this->extension) { + $extensionFile = $this->configuration->getExtensions()[$extension.'.php'] ?? null; + $this->extension = $this->loadExtension($extensionFile, 'Extensions\\'.$extension); + } + + return $this->extension->apply($item); + } + + private function loadExtension(\SplFileInfo $extension, string $extensionFile): ExtensionInterface + { + require_once $extension->getRealPath(); + + return new $extensionFile(ReadOnlyConfiguration::loadFromConfiguration($this->configuration), $this->getOptions()); + } +} \ No newline at end of file diff --git a/src/Component/Action/FilterAction.php b/src/Component/Action/FilterAction.php index 8848745d..d9760ac0 100644 --- a/src/Component/Action/FilterAction.php +++ b/src/Component/Action/FilterAction.php @@ -4,6 +4,7 @@ use Misery\Component\Common\Options\OptionsInterface; use Misery\Component\Common\Options\OptionsTrait; +use Misery\Component\Converter\Matcher; class FilterAction implements OptionsInterface { @@ -26,7 +27,7 @@ public function apply($item) { $field = $this->getOption('key', $this->getOption('field')); # legacy support $listItem = $item[$field] ?? null; - if (empty($listItem) || empty($field)) { + if (null === $listItem || null === $field) { return $item; } diff --git a/src/Component/Action/FilterFieldAction.php b/src/Component/Action/FilterFieldAction.php new file mode 100644 index 00000000..6c9c7e4f --- /dev/null +++ b/src/Component/Action/FilterFieldAction.php @@ -0,0 +1,65 @@ + [], + 'excludes' => [], + 'starts_with' => null, + 'ends_with' => null, + 'contains' => null, + 'reverse' => false, + 'clear_value' => false, + ]; + + public function apply($item) + { + $excludes = $this->getOption('excludes'); + $fields = $this->getOption('fields'); + $clearValue = $this->getOption('clear_value'); + // we want a reverse functionality when clearing values + if ($clearValue) { + $this->setOption('reverse', true); + } + + if ($fields !== []) { + foreach ($fields as $field) { + if (false === in_array($field, $excludes)) { + $item[$field] = null; + if (false === $clearValue) { + unset($item[$field]); + } + } + } + return $item; + } + + $startsWith = $this->getOption('starts_with'); + $endsWith = $this->getOption('ends_with'); + $contains = $this->getOption('contains'); + $reverse = $this->getOption('reverse'); + + $fields = array_filter(array_keys($item), function ($field) use ($startsWith, $endsWith, $contains, $reverse) { + return ($startsWith && \str_starts_with($field, $startsWith) === $reverse) || + ($endsWith && \str_ends_with($field, $endsWith) === $reverse) || + ($contains && \str_contains($field, $contains) === $reverse); + }); + + if ($fields !== []) { + $this->setOptions(['fields' => $fields]); + return $this->apply($item); + } + + return $item; + } +} \ No newline at end of file diff --git a/src/Component/Common/Cursor/ZoneFileIndexer.php b/src/Component/Common/Cursor/ZoneFileIndexer.php index 6e76fba0..a4fe4ccf 100644 --- a/src/Component/Common/Cursor/ZoneFileIndexer.php +++ b/src/Component/Common/Cursor/ZoneFileIndexer.php @@ -17,9 +17,11 @@ public function init(CursorInterface $cursor, string $reference): void if ($row) { $index = (int) $cursor->key(); # line number $zone = (int) (($index -1) / self::MEDIUM_CACHE_SIZE); # grouping number - $referenceValue = $row[$reference]; - $this->indexes[crc32($referenceValue)] = $index; - $this->zones[$index] = $zone; + $referenceValue = $row[$reference] ?? null; + if ($referenceValue) { + $this->indexes[crc32($referenceValue)] = $index; + $this->zones[$index] = $zone; + } } }); $cursor->rewind(); diff --git a/src/Component/Common/Pipeline/PipelineFactory.php b/src/Component/Common/Pipeline/PipelineFactory.php index b252fb7d..59a04689 100644 --- a/src/Component/Common/Pipeline/PipelineFactory.php +++ b/src/Component/Common/Pipeline/PipelineFactory.php @@ -41,6 +41,12 @@ public function createFromConfiguration( case $key === 'output' && isset($configuration['output']['writer']): $writer = $configurationManager->createWriter($configuration['output']['writer']); + + if (isset($configuration['output']['writer']['converter'])) { + $converter = $configurationManager->createConverter($configuration['output']['writer']['converter']); + $pipeline->line(new RevertPipe($converter)); + } + $pipeline->output(new PipeWriter($writer)); $pipeline->invalid( diff --git a/src/Component/Configurator/Configuration.php b/src/Component/Configurator/Configuration.php index 910aec74..f5734340 100644 --- a/src/Component/Configurator/Configuration.php +++ b/src/Component/Configurator/Configuration.php @@ -40,6 +40,8 @@ class Configuration private $accounts; private $isMultiStep = false; + private array $extensions = []; + public function __construct() { $this->converters = new ArrayCollection(); @@ -49,6 +51,21 @@ public function __construct() $this->blueprints = new ArrayCollection(); } + /** + * @return \SplFileInfo[] + */ + public function getExtensions(): array + { + return $this->extensions; + } + + public function setExtensions(\Traversable $files): void + { + foreach ($files as $file) { + $this->extensions[basename($file)] = $file; + } + } + public function isMultiStep(): bool { return $this->isMultiStep; diff --git a/src/Component/Configurator/ConfigurationManager.php b/src/Component/Configurator/ConfigurationManager.php index 92b2be16..f92245ad 100644 --- a/src/Component/Configurator/ConfigurationManager.php +++ b/src/Component/Configurator/ConfigurationManager.php @@ -73,6 +73,11 @@ public function __construct( if ($additionalSources) { $this->inMemoryFileManager->addFromFileManager($additionalSources); } + + $extensionsCursor = $additionalSources->find('Extensions/*'); + if ($extensionsCursor->current()) { + $this->config->setExtensions($extensionsCursor); + } } /** diff --git a/src/Component/Configurator/ReadOnlyConfiguration.php b/src/Component/Configurator/ReadOnlyConfiguration.php new file mode 100644 index 00000000..15741862 --- /dev/null +++ b/src/Component/Configurator/ReadOnlyConfiguration.php @@ -0,0 +1,69 @@ +sources = $configuration->getSources(); + $self->lists = $configuration->getLists(); + $self->filters = $configuration->getFilters(); + $self->mappings = $configuration->getMappings(); + + return $self; + } + + public function getSources(): SourceCollection + { + return $this->sources; + } + + public function getLists(): array + { + return $this->lists; + } + + public function getFilter(string $alias) + { + return $this->filters[$alias] ?? null; + } + + public function getFilters(): array + { + return $this->filters; + } + + public function getMappings(): array + { + return $this->getLists(); + } + + public function getMapping(string $alias) + { + return $this->getList($alias); + } +} \ No newline at end of file diff --git a/src/Component/Converter/Akeneo/Csv/Product.php b/src/Component/Converter/Akeneo/Csv/Product.php index c67e0771..6ce97036 100644 --- a/src/Component/Converter/Akeneo/Csv/Product.php +++ b/src/Component/Converter/Akeneo/Csv/Product.php @@ -9,6 +9,8 @@ use Misery\Component\Converter\AkeneoCsvHeaderContext; use Misery\Component\Converter\ConverterInterface; use Misery\Component\Converter\Matcher; +use Misery\Component\Decoder\ItemDecoder; +use Misery\Component\Decoder\ItemDecoderFactory; use Misery\Component\Encoder\ItemEncoder; use Misery\Component\Encoder\ItemEncoderFactory; use Misery\Component\Format\StringToBooleanFormat; @@ -20,9 +22,11 @@ class Product implements ConverterInterface, RegisteredByNameInterface, OptionsI private AkeneoCsvHeaderContext $csvHeaderContext; private ItemEncoder $encoder; + private ItemDecoder $decoder; private $options = [ - 'attribute_types:list' => null, + 'container' => 'values', + 'attribute_types:list' => null, # this key value list is optional, improves type matching for options, metrics, prices 'properties' => [ 'sku' => [ 'text' => null, @@ -46,15 +50,21 @@ class Product implements ConverterInterface, RegisteredByNameInterface, OptionsI public function __construct(AkeneoCsvHeaderContext $csvHeaderContext) { $this->csvHeaderContext = $csvHeaderContext; - $this->encoder = $this->ItemEncoderFactory()->createItemEncoder([ + list($encoder, $decoder) = $this->ItemEncoderDecoderFactory(); + $this->encoder = $encoder->createItemEncoder([ 'encode' => $this->getOption('properties'), 'parse' => $this->getOption('parse'), ]); + $this->decoder = $decoder->createItemDecoder([ + 'decode' => $this->getOption('properties'), + 'parse' => $this->getOption('parse'), + ]); } - private function ItemEncoderFactory(): ItemEncoderFactory + private function ItemEncoderDecoderFactory(): array { $encoderFactory = new ItemEncoderFactory(); + $decoderFactory = new ItemDecoderFactory(); $formatRegistry = new Registry('format'); $formatRegistry @@ -63,8 +73,9 @@ private function ItemEncoderFactory(): ItemEncoderFactory ; $encoderFactory->addRegistry($formatRegistry); + $decoderFactory->addRegistry($formatRegistry); - return $encoderFactory; + return [$encoderFactory, $decoderFactory]; } public function convert(array $item): array @@ -97,16 +108,18 @@ public function convert(array $item): array $prep = $this->csvHeaderContext->create($item)[$key]; $prep['data'] = $value; - # metrics - if ($codes[$masterKey] === 'pim_catalog_metric') { - $prep['data'] = [ - 'amount' => $value, - 'unit' => $item[str_replace($masterKey, $masterKey.'-unit', $key)] ?? null, - ]; - } - # multiselect - if ($codes[$masterKey] === 'pim_catalog_multiselect') { - $prep['data'] = array_filter(explode(',', $prep['data'])); + if (is_array($codes)) { + # metrics + if ($codes[$masterKey] === 'pim_catalog_metric') { + $prep['data'] = [ + 'amount' => $value, + 'unit' => $item[str_replace($masterKey, $masterKey.'-unit', $key)] ?? null, + ]; + } + # multiselect + if ($codes[$masterKey] === 'pim_catalog_multiselect') { + $prep['data'] = array_filter(explode(',', $prep['data'])); + } } $matcher = Matcher::create('values|'.$masterKey, $prep['locale'], $prep['scope']); @@ -122,7 +135,38 @@ public function convert(array $item): array public function revert(array $item): array { - return $item; + $container = $this->getOption('container'); + + $output = []; + $output['sku'] = $item['sku'] ?? $item['identifier'] ?? null; + $output['enabled'] = $item['enabled']; + $output['family'] = $item['family']; + $output['categories'] = $item['categories']; + $output['parent'] = $item['parent']; + $output = $this->decoder->decode($output); + + foreach ($item as $key => $itemValue) { + $matcher = $itemValue['matcher'] ?? null; + /** @var $matcher Matcher */ + if ($matcher && $matcher->matches($container)) { + unset($itemValue['matcher']); + unset($item[$key]); + if (is_array($itemValue['data']) && array_key_exists('unit', $itemValue['data'])) { + $output[$matcher->getRowKey()] = $itemValue['data']['amount']; + $output[$matcher->getRowKey().'-unit'] = $itemValue['data']['unit']; + continue; + } + if (is_array($itemValue['data'])) { + $output[$matcher->getRowKey()] = implode(',', $itemValue['data']); + continue; + } + if (isset($itemValue['data'])) { + $output[$matcher->getRowKey()] = $itemValue['data']; + } + } + } + + return $output; } public function getName(): string diff --git a/src/Component/Extension/ExtensionInterface.php b/src/Component/Extension/ExtensionInterface.php new file mode 100644 index 00000000..1828b139 --- /dev/null +++ b/src/Component/Extension/ExtensionInterface.php @@ -0,0 +1,8 @@ + $value) { + /** @var $matcher Matcher */ + if (is_array($value) && array_key_exists('matcher', $value)) { + $matcher = $value['matcher']; + $set[$matcher->getMainKey()] = $value['data']; + continue; + } + $filtered = is_array($value) ? array_diff($value, ['', '-']) : null; switch (true) { case is_numeric($value): diff --git a/src/bootstrap.php b/src/bootstrap.php index 3f59bbae..240d4ff8 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -127,6 +127,8 @@ ->register(Misery\Component\Action\FilterAction::NAME, new Misery\Component\Action\FilterAction()) ->register(Misery\Component\Action\PopAction::NAME, new Misery\Component\Action\PopAction()) ->register(Misery\Component\Action\ColumnValueMapperAction::NAME, new Misery\Component\Action\ColumnValueMapperAction()) + ->register(Misery\Component\Action\FilterFieldAction::NAME, new Misery\Component\Action\FilterFieldAction()) + ->register(Misery\Component\Action\ExtensionAction::NAME, new Misery\Component\Action\ExtensionAction()) ->register(\Misery\Component\Action\AkeneoValueFormatterAction::NAME, new Misery\Component\Action\AkeneoValueFormatterAction()) ->register(\Misery\Component\Action\ConvergenceAction::NAME, new Misery\Component\Action\ConvergenceAction()) ->register(\Misery\Component\Action\ConverterAction::NAME, new Misery\Component\Action\ConverterAction()) diff --git a/tests/Component/Action/DateTimeActionTest.php b/tests/Component/Action/DateTimeActionTest.php index aab9ccfe..14a0710c 100644 --- a/tests/Component/Action/DateTimeActionTest.php +++ b/tests/Component/Action/DateTimeActionTest.php @@ -171,4 +171,25 @@ public function testConvertTimeFormatValidCase() 'dateTime' => '6:30 pm' ], $dateTimeAction->apply($item)); } + + public function testConvertMappedFormatValidCase() + { + $dateTimeAction = new DateTimeAction(); + + $item = [ + 'sku' => '12', + 'dateTime' => '2023-10-18 18:30:00' + ]; + + $dateTimeAction->setOptions([ + 'field' => 'dateTime', + 'inputFormat' => 'Y-m-d H:i:s', + 'outputFormat' => 'COOKIE', + ]); + + $this->assertEquals([ + 'sku' => '12', + 'dateTime' => 'Wednesday, 18-Oct-2023 18:30:00 UTC' + ], $dateTimeAction->apply($item)); + } } \ No newline at end of file diff --git a/tests/Component/Action/EmptyActionTest.php b/tests/Component/Action/EmptyActionTest.php new file mode 100644 index 00000000..0b97a773 --- /dev/null +++ b/tests/Component/Action/EmptyActionTest.php @@ -0,0 +1,53 @@ + '123', 'values' => [ + 'nn_test' => [ + [ + 'locale' => null, + 'scope' => null, + 'data' => 'AB', + ], + ] + ]]; + + $action = new EmptyAction(); + $action->setOptions([ + 'field' => 'values', + 'list' => ['test'], + 'prefix' => 'nn_', + ]); + + $this->assertEquals(['sku' => '123', 'values' => [ + 'nn_test' => [ + [ + 'locale' => null, + 'scope' => null, + 'data' => null, + ], + ]]], $action->apply($item)); + + $action = new EmptyAction(); + $action->setOptions([ + 'field' => 'values', + 'list' => ['nn_test'], + ]); + + $this->assertEquals(['sku' => '123', 'values' => [ + 'nn_test' => [ + [ + 'locale' => null, + 'scope' => null, + 'data' => null, + ], + ]]], $action->apply($item)); + } +} \ No newline at end of file diff --git a/tests/Component/Action/FilterFieldActionTest.php b/tests/Component/Action/FilterFieldActionTest.php new file mode 100644 index 00000000..a54dbd1c --- /dev/null +++ b/tests/Component/Action/FilterFieldActionTest.php @@ -0,0 +1,173 @@ + 'louis', + 'description' => 'LV', + 'sku' => '1', + ]; + + $format->setOptions([ + 'fields' => ['brands'], + 'reverse' => true, + ]); + + $this->assertEquals( + $item + , $format->apply($item)); + } + + public function test_it_should_filter_fields_action(): void + { + $format = new FilterFieldAction(); + + $item = [ + 'brand' => 'louis', + 'description' => 'LV', + 'sku' => '1', + ]; + + $format->setOptions([ + 'fields' => ['brand'], + 'reverse' => true, + ]); + + $this->assertEquals( + [ + 'description' => 'LV', + 'sku' => '1', + ], + $format->apply($item) + ); + } + public function test_it_should_filter_matching_contains_fields_action(): void + { + $format = new FilterFieldAction(); + + $item = [ + 'values|section-1' => 'A', + 'values|section-2' => 'B', + 'values|section-3' => 'C', + 'values|descriptions' => 'D', + ]; + + # Contains + $format->setOptions([ + 'contains' => 'values|section-', + ]); + + $this->assertSame( + [ + 'values|section-1' => 'A', + 'values|section-2' => 'B', + 'values|section-3' => 'C', + ], + $format->apply($item) + ); + } + + public function test_it_should_filter_matching_start_with_fields_action(): void + { + $format = new FilterFieldAction(); + + $item = [ + 'values|section-1' => 'A', + 'values|section-2' => 'B', + 'values|section-3' => 'C', + 'values|descriptions' => 'D', + ]; + + $format->setOptions([ + 'starts_with' => 'values|section', + ]); + + $this->assertSame( + [ + 'values|section-1' => 'A', + 'values|section-2' => 'B', + 'values|section-3' => 'C', + ], + $format->apply($item) + ); + + $format = new FilterFieldAction(); + + $format->setOptions([ + 'starts_with' => 'values|', + ]); + + $this->assertSame( + $item, + $format->apply($item) + ); + } + + public function test_it_should_filter_matching_ends_with_fields_action(): void + { + $format = new FilterFieldAction(); + + $item = [ + 'values|section-1' => 'A', + 'values|section-2' => 'B', + 'values|section-3' => 'C', + 'values|descriptions' => 'D', + ]; + + # Ends with + $format->setOptions([ + 'ends_with' => 'ions', + ]); + + $this->assertSame( + [ + 'values|descriptions' => 'D', + ], + $format->apply($item) + ); + } + + public function test_it_should_clear_filtered_values_action(): void + { + $format = new FilterFieldAction(); + + $item = [ + 'brand' => 'louis', + 'description' => 'LV', + 'sku' => '1', + ]; + + $format->setOptions([ + 'fields' => ['brand'], + 'clear_value' => true, + ]); + + $this->assertEquals([ + 'brand' => null, + 'description' => 'LV', + 'sku' => '1', + ], $format->apply($item)); + + $format = new FilterFieldAction(); + + $format->setOptions([ + 'starts_with' => 'bran', + 'clear_value' => true, + ]); + + $this->assertEquals([ + 'brand' => null, + 'description' => 'LV', + 'sku' => '1', + ], $format->apply($item)); + } +} \ No newline at end of file diff --git a/tests/Component/Action/UnsetActionTest.php b/tests/Component/Action/UnsetActionTest.php index ab475394..a483cf3e 100644 --- a/tests/Component/Action/UnsetActionTest.php +++ b/tests/Component/Action/UnsetActionTest.php @@ -36,4 +36,26 @@ public function testApplyWithNonArrayField() $this->assertEquals(['field' => 'value'], $result); } + + public function testApplyUnsetEmptyKeys() + { + $item = ['field' => ['key1' => 'value1', 'key2' => 'value2', 'key3' => null]]; + + $action = new UnsetAction(); + $action->setOptions([ + 'field' => 'field', + 'empty_only' => true, + 'list' => ['key1', 'key2', 'key3'] + ]); + + $this->assertEquals(['field' => ['key1' => 'value1', 'key2' => 'value2']], $action->apply($item)); + + $action->setOptions([ + 'field' => 'field', + 'empty_only' => 1, + 'list' => ['key1', 'key2', 'key3'] + ]); + + $this->assertEquals(['field' => ['key1' => 'value1', 'key2' => 'value2']], $action->apply($item)); + } } diff --git a/tests/Component/Converter/Akeneo/Csv/ProductTest.php b/tests/Component/Converter/Akeneo/Csv/ProductTest.php index 375ae1ed..c93aacd2 100644 --- a/tests/Component/Converter/Akeneo/Csv/ProductTest.php +++ b/tests/Component/Converter/Akeneo/Csv/ProductTest.php @@ -77,19 +77,13 @@ public function testConvert() $this->assertEquals($this->getNormalizedData(), $converter->convert($this->inputData)); } -// public function testRevert() -// { -// $csvHeaderContext = new AkeneoCsvHeaderContext(); -// $converter = new Product($csvHeaderContext); -// $converter->setOptions([ -// 'attribute_types:list' => [ -// 'attribute1' => 'pim_catalog_text', -// 'attribute2' => 'pim_catalog_text', -// ], -// ]); -// -// $this->assertEquals($this->inputData, $converter->revert($this->getNormalizedData())); -// } + public function testRevert() + { + $csvHeaderContext = new AkeneoCsvHeaderContext(); + $converter = new Product($csvHeaderContext); + + $this->assertEquals($this->inputData, $converter->revert($this->getNormalizedData())); + } public function testName() {