# Fixture_.java

    /*
    ** Module   : Fixture_.java
    ** Abstract : Implementation of the OEUnit.Data.Fixture class.
    **
    ** Copyright (c) 2023-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -------------------------------Description--------------------------------
    ** 001 VVT 20230318 Created initial version
    ** 002 CA  20231113 The 'execute' method must be annotated with LegacySignature Type.Execute, and also can be
    **                  dropped if is a no-op.
    ** 003 CA  20250317 Added 'fixtures' variable.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.oo.oeunit.data;

    import static com.goldencode.p2j.report.ReportConstants.*;
    import static com.goldencode.p2j.util.BlockManager.*;

    import java.util.*;
    import java.util.function.*;

    import com.goldencode.p2j.oo.lang.*;
    import com.goldencode.p2j.persist.*;
    import com.goldencode.p2j.persist.lock.*;
    import com.goldencode.p2j.util.*;
    import com.goldencode.p2j.util.InternalEntry.*;

    /**
     * Implementation for OEUnit.Data.Fixture.
     */
    @LegacyResource(resource = "OEUnit.Data.Fixture")
    @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
    public class Fixture_
    extends BaseObject
    {
       @LegacySignature(type = Type.VARIABLE, name = "Fixtures")
       protected object<? extends com.goldencode.p2j.oo.oeunit.util.List> fixtures = TypeFactory.object(com.goldencode.p2j.oo.oeunit.util.List.class);

       /**
        * The list of datasets
        */
       protected final List<DataSet> datasets = new ArrayList<>();

       /**
        * The static constructor
        */
       @LegacySignature(type = Type.CONSTRUCTOR)
       public static void __oeunit_data_Fixture__constructor__static__()
       {
          externalProcedure(Fixture_.class, new Block((Body) () -> {
             onRoutineLevel(Condition.ERROR, Action.THROW);
          }));
       }

       /**
        * The constructor
        */
       @LegacySignature(type = Type.CONSTRUCTOR)
       public void __oeunit_data_Fixture__constructor__()
       {
          internalProcedure(Fixture_.class, this, "__oeunit_data_fixture__constructor__",
                   new Block((Body) () -> {
                      __lang_BaseObject_constructor__();
                   }));
       }

       /**
        * The destructor
        */
       @LegacySignature(type = Type.DESTRUCTOR)
       public void __oeunit_data_Fixture__destructor__()
       {
          internalProcedure(Fixture_.class, this, "__oeunit_data_Fixture__destructor__",
                   new Block((Body) () -> {
                      for(final DataSet ds : datasets)
                      {
                         ds.delete();
                      }}));
       }

       /**
        * The 'execute' method
        */
       @LegacySignature(type = Type.EXECUTE)
       public void __oeunit_data_Fixture__execute__()
       {
          onRoutineLevel(Condition.ERROR, Action.THROW);
       }

       /**
        * Create data in the attached databases, based on data in dataset tables.
        *
        * @return {@code true} if the operation succeeded, {@code false} if there is no
        * datasets in this fixture or any error occurred while creating data from the datasets.
        */
       public final boolean createData()
       {
          if (datasets.isEmpty())
          {
             return false;
          }

          for (final DataSet dsData : datasets)
          {
             final int numTopBuffers = dsData._getNumTopBuffers();
             for (int i = 0; i < numTopBuffers; i++)
             {
                // Note: counters are 1-based in OE
                final handle hBuffer = dsData.getTopBuffer(i + 1);
                if (!hBuffer._isValid())
                {
                   return false;
                }

                // HandleOps.delete(hQbuffer);
                final handle hQuerybuffer = TypeFactory.handle();
                RecordBuffer.create(hQuerybuffer, hBuffer);

                final character name = hBuffer.unwrap().name();
                final handle hDestbuffer = TypeFactory.handle();
                RecordBuffer.create(hDestbuffer, name);

                final handle hQuery = TypeFactory.handle();
                QueryWrapper.createQuery(hQuery);
                final P2JQuery query = hQuery.unwrapQuery();
                try
                {
                   if (!query.setBuffers(hQuerybuffer).booleanValue()
                            || !query.prepare("FOR EACH " + name.toStringMessage() + " NO-LOCK:").booleanValue()
                            || !query.queryOpen().booleanValue())
                   {
                      return false;
                   }

                   if (query.getFirst(LockType.LT_NONE).booleanValue())
                   {
                      final Buffer destBuffer = hDestbuffer.unwrapBuffer();
                      while (!query.isOffEnd().booleanValue())
                      {
                         destBuffer.bufferCreate();
                         destBuffer.bufferCopy(hQuerybuffer);
                         destBuffer.bufferRelease();

                         query.getNext();
                      }
                   }

                   query.queryClose();
                }
                finally
                {
                   HandleOps.delete(hDestbuffer);
                   HandleOps.delete(hQuerybuffer);
                   HandleOps.delete(hQuery);
                }
             }

          }

          return true;
       }

       /**
        * Initialize this fixture from a dataset.
        *
        * @param  _dsSrc
        *         the source dataset handle
        *
        * @return {@code true} if the operation succeeded
        */
       @LegacySignature(type = Type.METHOD, name = "FromDataSet", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "dsSrc", type = "HANDLE", mode = "INPUT") })
       public logical fromDataSet(final handle _dsSrc)
       {
          final handle dsSrc = TypeFactory.initInput(_dsSrc);
          return addDataset("FromDataSet", ds -> {
             return ds.copyDataset(dsSrc).booleanValue() ? ds : null;
          });
       }

       /**
        * Initialize from a JSON code.
        *
        * @param  json
        *         the JSON code
        *
        * @return {@code true} if the operation succeeded
        */
       @SuppressWarnings("resource")
       @LegacySignature(type = Type.METHOD, name = "FromJSON", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "json", type = "LONGCHAR", mode = "INPUT") })
       public logical fromJson(final Text json)
       {
          return addDataset("FromJSON", ds -> {
             return ds.readJson(new SourceData("LONGCHAR", json),
                      new character("EMPTY")).booleanValue() ? ds : null;
          });
       }

       /**
        * Initialize from a JSON file.
        *
        * @param  path
        *         the JSON file
        *
        * @return {@code true} if the operation succeeded
        */
       @SuppressWarnings("resource")
       @LegacySignature(type = Type.METHOD, name = "FromJSONFile", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "path", type = "CHARACTER", mode = "INPUT") })
       public logical fromJsonfile(final Text path)
       {
          return addDataset("FromJSONFile", ds -> {
             return ds.readJson(new SourceData("FILE", path),
                      new character("EMPTY")).booleanValue() ? ds : null;
          });
       }

       /**
        * Initialize from a TEMP-TABLE.
        *
        * @param  _ttSrc
        *         the source TEMP-TABLE handle
        *
        * @return {@code true} if the operation succeeded
        */
       @LegacySignature(type = Type.METHOD, name = "FromTempTable", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "ttSrc", type = "HANDLE", mode = "INPUT") })
       public logical fromTempTable(final handle _ttSrc)
       {
          final handle ttSrc = TypeFactory.initInput(_ttSrc);
          return addDataset("FromTempTable",
                   ds -> {
                      final handle ttData = TypeFactory.handle();
                      TempTableBuilder.create(ttData);
                      final logical res = ttData.unwrapTempTableDuplicator().copyTempTable(ttSrc,
                               new logical(false), new logical(false), new logical(false),
                               new character(""));
                      if (!res.booleanValue())
                      {
                         HandleOps.delete(ttData);
                         return null;
                      }

                      final handle ttDataBuf = ttData.unwrapTempTable().defaultBufferHandle();
                      ds.addBuffer(ttDataBuf);
                      return ds;
                   });
       }

       /**
        * Initialize from XML code.
        *
        * @param  xml
        *         source XML text
        *
        * @return {@code true} if the operation succeeded
        */
       @LegacySignature(type = Type.METHOD, name = "FromXML", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "xml", type = "LONGCHAR", mode = "INPUT") })
       public logical fromXml(final longchar xml)
       {
          return addDataset("FromXML", ds -> {
             return ds.readXml(new SourceData("LONGCHAR", xml),
                      new character("EMPTY"), new character(), new logical()).booleanValue() ? ds : null;
          });
       }

       /**
        * Initialize from an XML file.
        *
        * @param  path
        *         the XML file
        *
        * @return {@code true} if the operation succeeded
        */
       @LegacySignature(type = Type.METHOD, name = "FromXMLFile", returns = "LOGICAL", parameters = {
                @LegacyParameter(name = "path", type = "CHARACTER", mode = "INPUT") })
       public logical fromXmlfile(final character path)
       {
          return addDataset("FromXMLFile", ds -> {
             return ds.readXml(new SourceData("FILE", path),
                      new character("EMPTY"), new character(), new logical()).booleanValue() ? ds : null;
          });
       }

       /**
        * Get number of datasets in this fixture
        *
        * @return see above
        */
       @LegacySignature(type = Type.GETTER, name = "Size", returns = "INTEGER")
       public integer getSize()
       {
          return function(Fixture_.class, this, "Size", integer.class, new Block((Body) () -> {
             storeReturnValue(datasets.size());
          }));
       }

       /**
        * Get total number of tables in all datasets
        *
        * @return see above
        */
       @LegacySignature(type = Type.GETTER, name = "TableCount", returns = "INTEGER")
       public integer getTableCount()
       {
          return function(Fixture_.class, this, "TableCount", integer.class, new Block((Body) () -> {
             int result = 0;
             for (final DataSet ds : datasets)
             {
                result += ds != null ? ds.getNumTopBuffers().intValue() : 0;
             }

             storeReturnValue(result);
          }));
       }

       /**
        * Create, initialize and add a fixture dataset.
        *
        * @param  method
        *         the legacy method name
        * @param  initialize
        *         function to initialize dataset, on success returns the dataset, or error
        *         returns {@code null}
        *
        * @return {@code true} on success
        */
       private logical addDataset(final String method, final Function<DataSet, DataSet> initialize)
       {
          return function(Fixture_.class, this, method, logical.class, new Block((Body) () -> {
             final handle h = new handle();
             DataSet.create(h);
             final DataSet ds = (DataSet) h.getResource();
             assert ds != null;

             if (initialize.apply(ds) != null)
             {
                datasets.add(ds);
                storeReturnValue(true);
             }
             else
             {
                ds.delete();
                storeReturnValue(false);
             }
          }));
       }

    }