convert.test.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { convertOpenAISchemaToGemini } from '../lib/helper';
  2. import type { JsonSchemaObject } from '../lib/json_schema';
  3. import * as fs from 'node:fs';
  4. import * as path from 'node:path';
  5. // Create a simple test runner since we don't have Jest or Mocha installed
  6. function describe(name: string, fn: () => void) {
  7. console.log(`\n--- ${name} ---`);
  8. fn();
  9. }
  10. function it(name: string, fn: () => void) {
  11. console.log(`\n Test: ${name}`);
  12. try {
  13. fn();
  14. console.log(' ✅ PASSED');
  15. } catch (error) {
  16. console.error(' ❌ FAILED:', error);
  17. }
  18. }
  19. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  20. function expect(actual: unknown) {
  21. return {
  22. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  23. toEqual: (expected: unknown) => {
  24. const actualStr = JSON.stringify(actual);
  25. const expectedStr = JSON.stringify(expected);
  26. if (actualStr !== expectedStr) {
  27. throw new Error(`Expected ${expectedStr} but got ${actualStr}`);
  28. }
  29. },
  30. toBeTruthy: () => {
  31. if (!actual) {
  32. throw new Error(`Expected truthy value but got ${actual}`);
  33. }
  34. },
  35. };
  36. }
  37. describe('convertOpenAISchemaToGemini', () => {
  38. it('should convert OpenAI schema to Gemini format', () => {
  39. // Sample OpenAI schema with references and nullable properties
  40. const openaiSchema: JsonSchemaObject = {
  41. type: 'object',
  42. properties: {
  43. name: {
  44. type: 'string',
  45. description: 'The name of the user',
  46. },
  47. age: {
  48. type: 'number',
  49. description: 'The age of the user',
  50. },
  51. address: {
  52. $ref: '#/$defs/Address',
  53. },
  54. email: {
  55. anyOf: [{ type: 'string', description: 'Email address' }, { type: 'null' }],
  56. },
  57. tags: {
  58. type: 'array',
  59. items: {
  60. type: 'string',
  61. },
  62. },
  63. profile: {
  64. $ref: '#/$defs/Profile',
  65. },
  66. },
  67. required: ['name', 'age'],
  68. $defs: {
  69. Address: {
  70. type: 'object',
  71. properties: {
  72. street: { type: 'string' },
  73. city: { type: 'string' },
  74. zipCode: { type: 'string' },
  75. },
  76. required: ['street', 'city'],
  77. },
  78. Profile: {
  79. type: 'object',
  80. properties: {
  81. bio: { type: 'string' },
  82. website: {
  83. anyOf: [{ type: 'string' }, { type: 'null' }],
  84. },
  85. },
  86. },
  87. },
  88. };
  89. // Convert the schema
  90. const geminiSchema = convertOpenAISchemaToGemini(openaiSchema);
  91. // Expected Gemini schema
  92. const expectedGeminiSchema: JsonSchemaObject = {
  93. type: 'object',
  94. properties: {
  95. name: {
  96. type: 'string',
  97. description: 'The name of the user',
  98. },
  99. age: {
  100. type: 'number',
  101. description: 'The age of the user',
  102. },
  103. address: {
  104. type: 'object',
  105. properties: {
  106. street: { type: 'string' },
  107. city: { type: 'string' },
  108. zipCode: { type: 'string' },
  109. },
  110. required: ['street', 'city'],
  111. },
  112. email: {
  113. type: 'string',
  114. description: 'Email address',
  115. nullable: true,
  116. },
  117. tags: {
  118. type: 'array',
  119. items: {
  120. type: 'string',
  121. },
  122. },
  123. profile: {
  124. type: 'object',
  125. properties: {
  126. bio: { type: 'string' },
  127. website: {
  128. type: 'string',
  129. nullable: true,
  130. },
  131. },
  132. required: [],
  133. },
  134. },
  135. required: ['name', 'age'],
  136. };
  137. // Verify the conversion
  138. expect(geminiSchema).toEqual(expectedGeminiSchema);
  139. // Write the schemas to files for manual inspection
  140. const testDir = path.join(__dirname, 'output');
  141. if (!fs.existsSync(testDir)) {
  142. fs.mkdirSync(testDir, { recursive: true });
  143. }
  144. fs.writeFileSync(path.join(testDir, 'openai.json'), JSON.stringify(openaiSchema, null, 2));
  145. fs.writeFileSync(path.join(testDir, 'gemini.json'), JSON.stringify(geminiSchema, null, 2));
  146. });
  147. it('should convert the actual json_schema.ts to gemini.json', () => {
  148. // Import the actual schema from json_schema.ts
  149. // eslint-disable-next-line @typescript-eslint/no-var-requires
  150. const { jsonNavigatorOutputSchema } = require('../lib/json_schema');
  151. // Convert the schema
  152. const geminiSchema = convertOpenAISchemaToGemini(jsonNavigatorOutputSchema);
  153. // Write the converted schema to a file
  154. const outputDir = path.join(__dirname, '../');
  155. fs.writeFileSync(path.join(outputDir, 'gemini.json'), JSON.stringify(geminiSchema, null, 2));
  156. // Verify the conversion was successful
  157. expect(geminiSchema).toBeTruthy();
  158. expect(geminiSchema.properties).toBeTruthy();
  159. });
  160. });