diff options
| -rw-r--r-- | .babelrc | 7 | ||||
| -rw-r--r-- | .github/workflows/deploy.yml (renamed from .github/workflows/nodejs.yml) | 17 | ||||
| -rw-r--r-- | .github/workflows/test.yml | 15 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | jest.config.js | 194 | ||||
| -rw-r--r-- | package.json | 5 | ||||
| -rw-r--r-- | webAO/__tests__/iniParse.test.js | 47 | ||||
| -rw-r--r-- | webAO/client.js | 39 | ||||
| -rw-r--r-- | webAO/iniParse.js | 42 |
9 files changed, 319 insertions, 49 deletions
diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..78e681f --- /dev/null +++ b/.babelrc @@ -0,0 +1,7 @@ +{ + "env": { + "test": { + "plugins": ["@babel/plugin-transform-modules-commonjs"] + } + } + }
\ No newline at end of file diff --git a/.github/workflows/nodejs.yml b/.github/workflows/deploy.yml index b37178b..d1bbeaa 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/deploy.yml @@ -1,26 +1,21 @@ -name: Node CI +name: Deploy CI on: [push] jobs: build: - runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v1 - name: Setup Node uses: actions/setup-node@v1 - - name: npm install, build, and test - run: | - git submodule init - git submodule update - npm install - npm ci - npm run build + - name: Install Dependencies + run: npm install + - name: Build Project + run: npm build - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@4.0.0 with: branch: gh-pages # The branch the action should deploy to. - folder: webAO # The folder the action should deploy. + folder: webAO # The folder the action should deploy.
\ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d5f9f79 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,15 @@ +name: Test CI + +on: [pull_request] +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Setup Node + uses: actions/setup-node@v1 + - name: Install Dependencies + run: npm install + - name: Run Tests + run: npm test
\ No newline at end of file @@ -2,6 +2,8 @@ Thumbs.db ehthumbs.db +coverage/ + # Folder config file Desktop.ini diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..2506cf3 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,194 @@ +/* + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +module.exports = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "C:\\Users\\razen\\AppData\\Local\\Temp\\jest", + + // Automatically clear mock calls, instances and results before every test + // clearMocks: false, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: 'coverage', + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "\\\\node_modules\\\\" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'babel', + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "<rootDir>" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: 'jsdom', + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "\\\\node_modules\\\\" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "\\\\node_modules\\\\", + // "\\.pnp\\.[^\\\\]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/package.json b/package.json index 7971138..27fd577 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "babel": "babel ui.js -o ui.b.js", "webpack": "webpack", "deploy": "cross-env NODE_ENV=production webpack -p", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jest", + "test:coverage": "jest --coverage", "build": "webpack --config webpack.config.js", "start": "webpack serve --config webpack.config.js", "lint": "eslint . --ext .js", @@ -24,12 +25,14 @@ "homepage": "https://github.com/AttorneyOnline/webAO#readme", "devDependencies": { "@babel/core": "^7.17.5", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", "@babel/preset-env": "^7.16.11", "babel-loader": "^8.2.3", "dotenv": "^16.0.0", "eslint": "^8.10.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.25.4", + "jest": "^27.5.1", "webpack": "^5.69.1", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4" diff --git a/webAO/__tests__/iniParse.test.js b/webAO/__tests__/iniParse.test.js new file mode 100644 index 0000000..deb08f3 --- /dev/null +++ b/webAO/__tests__/iniParse.test.js @@ -0,0 +1,47 @@ +import iniParse from '../iniParse'; + +const iniExample = ` +[Options] +name = Matt +showname = Matty + +[Emotions] +number = 9 +1 = Normal#-#normal#0#1 +`; +describe('iniParse', () => { + test('should not lowercase value if key is showname', () => { + const parsedIni = iniParse(` + [test] + showname = MATT + `); + expect(parsedIni.test.showname).toBe('MATT'); + }); + test('should lowercase value if key is not showname', () => { + const parsedIni = iniParse(` + [test] + party = TIME + `); + expect(parsedIni.test.party).toBe('time'); + }); + test('should parse sections', () => { + const parsedIni = iniParse(iniExample); + expect(Object.keys(parsedIni).length).toBe(2); + }); + test('should parse parameters', () => { + const parsedIni = iniParse(iniExample); + expect(Object.keys(parsedIni.options).length).toBe(2); + }); + test('should remove empty lines', () => { + const parsedIni = iniParse(` + [test] + + + 1 = 1 + 2 = 2 + + + `); + expect(Object.keys(parsedIni.test).length).toBe(2); + }); +}); diff --git a/webAO/client.js b/webAO/client.js index 7ff561b..eb7c7a2 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -18,6 +18,7 @@ import vanilla_background_arr from './backgrounds.js'; import vanilla_evidence_arr from './evidence.js'; import chatbox_arr from './styles/chatbox/chatboxes.js'; +import iniParse from './iniParse'; const version = process.env.npm_package_version; @@ -843,7 +844,7 @@ class Client extends EventEmitter { // If the ini doesn't exist on the server this will throw an error try { const cinidata = await request(`${AO_HOST}characters/${encodeURI(chargs[0].toLowerCase())}/char.ini`); - cini = INI.parse(cinidata); + cini = iniParse(cinidata); } catch (err) { cini = {}; img.classList.add('noini'); @@ -2410,42 +2411,6 @@ class Viewport { } } -class INI { - static parse(data) { - const regex = { - section: /^\s*\[\s*([^\]]*)\s*\]\s*$/, - param: /^\s*([\w.\-_]+)\s*=\s*(.*?)\s*$/, - comment: /^\s*;.*$/, - }; - const value = {}; - const lines = data.split(/\r\n|\r|\n/); - let section; - lines.forEach((line) => { - if (regex.comment.test(line)) { - - } else if (line.length === 0) { - - } else if (regex.param.test(line)) { - const match = line.match(regex.param); - if (section) { - if (match[1].toLowerCase() === 'showname') { // don't lowercase the showname - value[section].showname = match[2]; - } else { - value[section][match[1].toLowerCase()] = match[2].toLowerCase(); - } - // } else { // we don't care about attributes without a section - // value[match[1]] = match[2]; - } - } else if (regex.section.test(line)) { - const match = line.match(regex.section); - value[match[1].toLowerCase()] = {}; // lowercase everything else - section = match[1].toLowerCase(); - } - }); - return value; - } -} - /** * read a cookie from storage * got this from w3schools diff --git a/webAO/iniParse.js b/webAO/iniParse.js new file mode 100644 index 0000000..fb04e67 --- /dev/null +++ b/webAO/iniParse.js @@ -0,0 +1,42 @@ +const regexPatterns = { + section: /^\s*\[\s*([^\]]*)\s*\]\s*$/, + param: /^\s*([\w.\-_]+)\s*=\s*(.*?)\s*$/, + comment: /^\s*;.*$/, +}; + +const valueHandler = (matchKey, matchValue) => (matchKey === 'showname' ? matchValue : matchValue.toLowerCase()); + +const lineFilter = (value) => { + const isEmpty = value.length === 0; + const isComment = regexPatterns.comment.test(value); + if (isComment || isEmpty) { + return false; + } + return true; +}; + +const iniParse = (data) => { + const parsedIni = {}; + const lines = data.split(/\r\n|\r|\n/); + const filteredLines = lines.filter(lineFilter); + + let currentSection; + filteredLines.forEach((line) => { + const isParameter = regexPatterns.param.test(line); + const isSection = regexPatterns.section.test(line); + if (isParameter && currentSection) { + const match = line.match(regexPatterns.param); + const matchKey = match[1].toLowerCase(); + const matchValue = match[2]; + parsedIni[currentSection][matchKey] = valueHandler(matchKey, matchValue); + } else if (isSection) { + const match = line.match(regexPatterns.section); + const matchKey = match[1].toLowerCase(); + parsedIni[matchKey] = {}; + currentSection = matchKey; + } + }); + return parsedIni; +}; + +export default iniParse; |
